diff --git a/app/assets/stylesheets/admin/budgets/actions.scss b/app/assets/stylesheets/admin/budgets/actions.scss index 03b82fd6b..c72a6bfac 100644 --- a/app/assets/stylesheets/admin/budgets/actions.scss +++ b/app/assets/stylesheets/admin/budgets/actions.scss @@ -42,6 +42,10 @@ @include hollow-button; } + .ballots-link { + @include regular-button; + } + .destroy-link { @include regular-button($alert-color); @@ -56,6 +60,7 @@ } .calculate-winners-link, + .ballots-link, .destroy-link { margin-bottom: 0; } diff --git a/app/assets/stylesheets/admin/budgets/links.scss b/app/assets/stylesheets/admin/budgets/links.scss index a107f700b..3326ba75b 100644 --- a/app/assets/stylesheets/admin/budgets/links.scss +++ b/app/assets/stylesheets/admin/budgets/links.scss @@ -26,6 +26,11 @@ @include icon-on-top; } + .ballots-link { + @include has-fa-icon(archive, solid); + color: $link; + } + .results-link { @include has-fa-icon(poll, solid); } diff --git a/app/assets/stylesheets/mixins/icons.scss b/app/assets/stylesheets/mixins/icons.scss index 8c7317e78..5b68f75a1 100644 --- a/app/assets/stylesheets/mixins/icons.scss +++ b/app/assets/stylesheets/mixins/icons.scss @@ -1618,8 +1618,7 @@ $font-awesome-icons: ( color: $color-success; } - .manage-link, - .ballots-link { + .manage-link { @include has-fa-icon(archive, solid); color: $link; } diff --git a/app/components/admin/budgets/actions_component.rb b/app/components/admin/budgets/actions_component.rb index 0728f4a93..07c515b81 100644 --- a/app/components/admin/budgets/actions_component.rb +++ b/app/components/admin/budgets/actions_component.rb @@ -22,6 +22,10 @@ class Admin::Budgets::ActionsComponent < ApplicationComponent hint: winners_hint, html: winners_action }, + ballots: { + hint: t("admin.budgets.actions.descriptions.ballots"), + html: ballots_action + }, destroy: { hint: destroy_hint, html: destroy_action @@ -55,6 +59,27 @@ class Admin::Budgets::ActionsComponent < ApplicationComponent end end + def ballots_action + if budget.published? && !budget.balloting_finished? && !budget.poll.present? + action(:ballots, + text: t("admin.budgets.actions.ballots"), + path: create_budget_poll_path, + method: :post, + confirm: t("admin.budgets.actions.confirm.ballots")) + end + end + + def create_budget_poll_path + balloting_phase = budget.phases.find_by(kind: "balloting") + + admin_polls_path(poll: { + name: budget.name, + budget_id: budget.id, + starts_at: balloting_phase.starts_at, + ends_at: balloting_phase.ends_at + }) + end + def descriptor_id(action_name) "#{dom_id(budget, action_name)}_descriptor" end diff --git a/app/components/admin/budgets/links_component.html.erb b/app/components/admin/budgets/links_component.html.erb index c8afc722b..6b73f9f3b 100644 --- a/app/components/admin/budgets/links_component.html.erb +++ b/app/components/admin/budgets/links_component.html.erb @@ -5,6 +5,12 @@ path: admin_budget_budget_investments_path(budget)) %> <% end %> + <% if budget.poll.present? %> + <%= action(:ballots, + text: t("admin.budgets.index.admin_ballots"), + path: admin_poll_booth_assignments_path(budget.poll)) %> + <% end %> + <% if can?(:read_results, budget) %> <%= action(:results, text: results_text, path: budget_results_path(budget)) %> <% else %> diff --git a/app/components/admin/budgets/table_actions_component.html.erb b/app/components/admin/budgets/table_actions_component.html.erb index c6f5ada52..45f7e831b 100644 --- a/app/components/admin/budgets/table_actions_component.html.erb +++ b/app/components/admin/budgets/table_actions_component.html.erb @@ -2,18 +2,4 @@ <%= actions.action(:investments, text: t("admin.budgets.index.budget_investments"), path: admin_budget_budget_investments_path(budget)) %> - <% if budget.poll.present? %> - <%= actions.action(:ballots, - text: t("admin.budgets.index.admin_ballots"), - path: admin_poll_booth_assignments_path(budget.poll)) %> - <% else %> - <%= actions.action(:ballots, - text: t("admin.budgets.index.admin_ballots"), - path: create_budget_poll_path, - method: :post) %> - <% end %> - <%= actions.action(:preview, - text: t("admin.budgets.actions.preview"), - path: budget_path(budget), - target: "_blank") %> <% end %> diff --git a/app/components/admin/budgets/table_actions_component.rb b/app/components/admin/budgets/table_actions_component.rb index 92277c152..2ac537bb3 100644 --- a/app/components/admin/budgets/table_actions_component.rb +++ b/app/components/admin/budgets/table_actions_component.rb @@ -7,17 +7,6 @@ class Admin::Budgets::TableActionsComponent < ApplicationComponent private - def create_budget_poll_path - balloting_phase = budget.phases.find_by(kind: "balloting") - - admin_polls_path(poll: { - name: budget.name, - budget_id: budget.id, - starts_at: balloting_phase.starts_at, - ends_at: balloting_phase.ends_at - }) - end - def actions_component Admin::TableActionsComponent.new( budget, diff --git a/config/locales/en/admin.yml b/config/locales/en/admin.yml index c834727f9..5e04255ff 100644 --- a/config/locales/en/admin.yml +++ b/config/locales/en/admin.yml @@ -69,9 +69,12 @@ en: no_activity: There are no moderators activity. budgets: actions: + ballots: "Create booths" confirm: + ballots: "Are you sure? This action is only necessary if you're going to use physical booths during the final voting phase. Citizens will still be able to vote via web with or without physical booths." destroy: "Are you sure? This will delete the budget and all its associated groups and headings. This action cannot be undone." descriptions: + ballots: "This will let you manage physical ballots. Only use this option if you're going to use physical booths to collect ballots during the final voting phase." calculate_winners: 'After calculating the results, only administrators will be able to access them. They will be public when the project reaches the "%{phase}" phase if the option "Show results" is enabled when editing the budget.' destroy: "This will delete the budget and all its associated groups and headers. This action cannot be undone." edit: "Edit budget" diff --git a/config/locales/es/admin.yml b/config/locales/es/admin.yml index d9122a158..0269be9d0 100644 --- a/config/locales/es/admin.yml +++ b/config/locales/es/admin.yml @@ -69,9 +69,12 @@ es: no_activity: No hay actividad de moderadores. budgets: actions: + ballots: "Crear urnas" confirm: + ballots: "¿Seguro? Esta acción solo es necesaria si vas a utilizar urnas físicas durante la votación final. Los ciudadanos podrán votar mediante la web con o sin urnas físicas." destroy: "¿Seguro? Esta acción borrará el presupuesto y todos sus grupos y partidas. Esta acción no se puede deshacer." descriptions: + ballots: "Esta acción te permitirá gestionar las urnas de votación. Usa esta opción solamente si vas a utilizar urnas físicas para recoger votos durante la votación final." calculate_winners: 'Tras calcular los resultados, solamente los administradores tendrán acceso a los mismos. Se harán públicos cuando el presupuesto llegue a la fase "%{phase}" si se habilita la opción "Mostrar resultados" al editar el presupuesto.' destroy: "Esta acción borrará el presupuesto y todos sus grupos y partidas. Esta acción no se puede deshacer." edit: "Editar presupuesto" diff --git a/spec/components/admin/budgets/actions_component_spec.rb b/spec/components/admin/budgets/actions_component_spec.rb new file mode 100644 index 000000000..106b9b3ea --- /dev/null +++ b/spec/components/admin/budgets/actions_component_spec.rb @@ -0,0 +1,34 @@ +require "rails_helper" + +describe Admin::Budgets::ActionsComponent, controller: Admin::BaseController do + before { sign_in(create(:administrator).user) } + + let(:budget) { create(:budget) } + let(:component) { Admin::Budgets::ActionsComponent.new(budget) } + + describe "Create booths button" do + it "is rendered for budgets without polls" do + render_inline component + + expect(page.find("form[action*='polls'][method='post']")).to have_button "Create booths" + end + + it "is not rendered for finished budgets without polls" do + budget.update!(phase: "finished") + + render_inline component + + expect(page).not_to have_css "form[action*='polls']" + expect(page).not_to have_button "Create booths" + end + + it "is not rendered for budgets with polls" do + budget.poll = create(:poll, budget: budget) + + render_inline component + + expect(page).not_to have_css "form[action*='polls']" + expect(page).not_to have_button "Create booths" + end + end +end diff --git a/spec/components/admin/budgets/links_component_spec.rb b/spec/components/admin/budgets/links_component_spec.rb index 3013d5d25..997b1b6bd 100644 --- a/spec/components/admin/budgets/links_component_spec.rb +++ b/spec/components/admin/budgets/links_component_spec.rb @@ -97,4 +97,24 @@ describe Admin::Budgets::LinksComponent, controller: Admin::BaseController do expect(page).not_to have_link "Investment projects" end end + + describe "ballots link" do + let(:budget) { create(:budget) } + let(:component) { Admin::Budgets::LinksComponent.new(budget) } + + it "is rendered for budgets with polls" do + budget.poll = create(:poll, budget: budget) + path = Rails.application.routes.url_helpers.admin_poll_booth_assignments_path(budget.poll) + + render_inline component + + expect(page).to have_link "Ballots", href: path + end + + it "is not rendered for budgets without polls" do + render_inline component + + expect(page).not_to have_link "Ballots" + end + end end diff --git a/spec/components/admin/budgets/table_actions_component_spec.rb b/spec/components/admin/budgets/table_actions_component_spec.rb index 7f320da9e..39dd13b43 100644 --- a/spec/components/admin/budgets/table_actions_component_spec.rb +++ b/spec/components/admin/budgets/table_actions_component_spec.rb @@ -4,29 +4,13 @@ describe Admin::Budgets::TableActionsComponent, controller: Admin::BaseControlle let(:budget) { create(:budget) } let(:component) { Admin::Budgets::TableActionsComponent.new(budget) } - it "renders actions to edit budget, manage investments and manage ballots" do + it "renders actions to edit budget and manage investments" do render_inline component - expect(page).to have_link count: 3 + expect(page).to have_link count: 2 expect(page).to have_link "Investment projects", href: /investments/ expect(page).to have_link "Edit", href: /#{budget.id}\Z/ - expect(page).to have_link "Preview", href: /budgets/ - expect(page).to have_button count: 1 - expect(page).to have_button "Ballots" - end - - it "renders button to create new poll for budgets without polls" do - render_inline component - - expect(page).to have_css "form[action*='polls'][method='post']", exact_text: "Ballots" - end - - it "renders link to manage ballots for budgets with polls" do - budget.poll = create(:poll, budget: budget) - - render_inline component - - expect(page).to have_link "Ballots", href: /booth_assignments/ + expect(page).not_to have_button end end diff --git a/spec/system/budget_polls/budgets_spec.rb b/spec/system/budget_polls/budgets_spec.rb index a92fdf800..bb5152f76 100644 --- a/spec/system/budget_polls/budgets_spec.rb +++ b/spec/system/budget_polls/budgets_spec.rb @@ -6,9 +6,9 @@ describe "Admin Budgets", :admin do budget = create(:budget) balloting_phase = budget.phases.balloting - visit admin_budgets_path + visit admin_budget_path(budget) - click_button "Ballots" + accept_confirm { click_button "Create booths" } expect(page).to have_current_path(/admin\/polls\/\d+/) expect(page).to have_content(budget.name) @@ -17,28 +17,17 @@ describe "Admin Budgets", :admin do end scenario "Create poll in current locale if the budget does not have a poll associated" do - create(:budget, - name_en: "Budget for climate change", - name_fr: "Budget pour le changement climatique") + budget = create(:budget, + name_en: "Budget for climate change", + name_es: "Presupuesto por el cambio climático") - visit admin_budgets_path - select "Français", from: "Language:" + visit admin_budget_path(budget) + select "Español", from: "Language:" - click_button "Bulletins de l’admin" + accept_confirm { click_button "Crear urnas" } expect(page).to have_current_path(/admin\/polls\/\d+/) - expect(page).to have_content("Budget pour le changement climatique") - end - - scenario "Display link to poll if the budget has a poll associated" do - budget = create(:budget) - poll = create(:poll, budget: budget) - - visit admin_budgets_path - - within "#budget_#{budget.id}" do - expect(page).to have_link "Ballots", href: admin_poll_booth_assignments_path(poll) - end + expect(page).to have_content "Presupuesto por el cambio climático" end end