diff --git a/app/controllers/admin/proposals_controller.rb b/app/controllers/admin/proposals_controller.rb index e76efce21..7e53d1a46 100644 --- a/app/controllers/admin/proposals_controller.rb +++ b/app/controllers/admin/proposals_controller.rb @@ -6,8 +6,22 @@ class Admin::ProposalsController < Admin::BaseController has_orders %w[created_at] + before_action :load_proposal, except: :index + def show - @proposal = Proposal.find(params[:id]) + end + + def update + if @proposal.update(proposal_params) + redirect_to admin_proposal_path(@proposal), notice: t("admin.proposals.update.notice") + else + render :show + end + end + + def toggle_selection + @proposal.toggle :selected + @proposal.save! end private @@ -15,4 +29,13 @@ class Admin::ProposalsController < Admin::BaseController def resource_model Proposal end + + def load_proposal + @proposal = Proposal.find(params[:id]) + end + + def proposal_params + params.require(:proposal).permit(:selected) + end + end diff --git a/app/controllers/proposals_controller.rb b/app/controllers/proposals_controller.rb index 5cc9b7e10..52c16f0e0 100644 --- a/app/controllers/proposals_controller.rb +++ b/app/controllers/proposals_controller.rb @@ -51,6 +51,7 @@ class ProposalsController < ApplicationController discard_draft discard_archived load_retired + load_selected load_featured end @@ -139,6 +140,10 @@ class ProposalsController < ApplicationController end end + def load_selected + @resources = @resources.selected if params[:selected].present? + end + def load_featured return unless !@advanced_search_terms && @search_terms.blank? && @tag_filter.blank? && params[:retired].blank? && @current_order != "recommendations" if Setting["feature.featured_proposals"] diff --git a/app/helpers/proposals_helper.rb b/app/helpers/proposals_helper.rb index 633f469a3..3cc0ba03a 100644 --- a/app/helpers/proposals_helper.rb +++ b/app/helpers/proposals_helper.rb @@ -64,4 +64,39 @@ module ProposalsHelper proposals_current_view == "default" ? "minimal" : "default" end + def link_to_toggle_proposal_selection(proposal) + if proposal.selected? + button_text = t("admin.proposals.index.selected") + html_class = "button expanded" + else + button_text = t("admin.proposals.index.select") + html_class = "button hollow expanded" + end + + link_to button_text, + toggle_selection_admin_proposal_path(proposal), + remote: true, + method: :patch, + class: html_class + end + + def css_for_proposal_info_row + if feature?(:allow_images) + if params[:selected].present? + "small-12 medium-9 column" + else + "small-12 medium-6 large-7 column" + end + else + if params[:selected].present? + "small-12 column" + else + "small-12 medium-9 column" + end + end + end + + def show_proposal_votes? + params[:selected].blank? + end end diff --git a/app/views/admin/proposals/_form.html.erb b/app/views/admin/proposals/_form.html.erb new file mode 100644 index 000000000..b6dc1c442 --- /dev/null +++ b/app/views/admin/proposals/_form.html.erb @@ -0,0 +1,9 @@ +<%= form_for [:admin, @proposal] do |f| %> + + <%= render "shared/errors", resource: @proposal %> + + <%= f.check_box :selected %> + + <%= f.submit t("admin.proposals.form.update"), class: "button success" %> + +<% end %> diff --git a/app/views/admin/proposals/_select_proposal.html.erb b/app/views/admin/proposals/_select_proposal.html.erb new file mode 100644 index 000000000..d5d2069ab --- /dev/null +++ b/app/views/admin/proposals/_select_proposal.html.erb @@ -0,0 +1 @@ +<%= link_to_toggle_proposal_selection(proposal) %> diff --git a/app/views/admin/proposals/index.html.erb b/app/views/admin/proposals/index.html.erb index 8a8372713..bc59de812 100644 --- a/app/views/admin/proposals/index.html.erb +++ b/app/views/admin/proposals/index.html.erb @@ -16,6 +16,7 @@ <%= t("admin.proposals.index.title") %> <%= t("admin.proposals.index.author") %> <%= t("admin.proposals.index.milestones") %> + <%= t("admin.proposals.index.selected") %> @@ -26,6 +27,7 @@ <%= link_to proposal.title, admin_proposal_path(proposal) %> <%= proposal.author.username %> <%= proposal.milestones.count %> + <%= render "select_proposal", proposal: proposal %> <% end %> diff --git a/app/views/admin/proposals/show.html.erb b/app/views/admin/proposals/show.html.erb index 13fbce01e..afb2379e3 100644 --- a/app/views/admin/proposals/show.html.erb +++ b/app/views/admin/proposals/show.html.erb @@ -26,4 +26,10 @@ <%= render "proposals/info", proposal: @proposal %> +
+
+ <%= render "form" %> +
+
+ <%= render "admin/milestones/milestones", milestoneable: @proposal %> diff --git a/app/views/admin/proposals/toggle_selection.js.erb b/app/views/admin/proposals/toggle_selection.js.erb new file mode 100644 index 000000000..4963b7b7c --- /dev/null +++ b/app/views/admin/proposals/toggle_selection.js.erb @@ -0,0 +1 @@ +$("#<%= dom_id(@proposal) %> .js-select").html('<%= j render("select_proposal", proposal: @proposal) %>'); diff --git a/app/views/proposals/_proposal.html.erb b/app/views/proposals/_proposal.html.erb index 97224172a..bad37f0ee 100644 --- a/app/views/proposals/_proposal.html.erb +++ b/app/views/proposals/_proposal.html.erb @@ -12,10 +12,10 @@ alt: proposal.image.title.unicode_normalize %> -
+
<% else %>
-
+
<% end %>
<% cache [locale_and_user_status(proposal), "index", proposal, proposal.author] do %> @@ -62,24 +62,27 @@
-
- <% if proposal.successful? %> -
-

- <%= t("proposals.proposal.successful") %> -

-
- <% elsif proposal.archived? %> -
- <%= t("proposals.proposal.supports", count: proposal.total_votes) %> -

<%= t("proposals.proposal.archived") %>

-
- <% else %> - <%= render "votes", - { proposal: proposal, vote_url: vote_proposal_path(proposal, value: "yes") } %> - <% end %> -
+ <% if show_proposal_votes? %> +
+ <% if proposal.successful? %> +
+

+ <%= t("proposals.proposal.successful") %> +

+
+ <% elsif proposal.archived? %> +
+ <%= t("proposals.proposal.supports", count: proposal.total_votes) %> +

<%= t("proposals.proposal.archived") %>

+
+ <% else %> + <%= render "votes", + { proposal: proposal, vote_url: vote_proposal_path(proposal, value: "yes") } %> + <% end %> +
+ <% end %> +
diff --git a/app/views/proposals/_selected.html.erb b/app/views/proposals/_selected.html.erb new file mode 100644 index 000000000..2d8f272e2 --- /dev/null +++ b/app/views/proposals/_selected.html.erb @@ -0,0 +1,8 @@ +<% if params[:selected].blank? %> + + + +

+ <%= link_to t("proposals.index.selected_proposals"), proposals_path(selected: "all"), class: "small" %> +

+<% end %> diff --git a/app/views/proposals/index.html.erb b/app/views/proposals/index.html.erb index fff4a7bed..5729a92c1 100644 --- a/app/views/proposals/index.html.erb +++ b/app/views/proposals/index.html.erb @@ -9,7 +9,13 @@ <% end %>
- <% if @search_terms || @advanced_search_terms || @tag_filter || params[:retired].present? %> + <% if [ + @search_terms, + @advanced_search_terms, + @tag_filter, + params[:retired].present?, + params[:selected].present? + ].any? %>
@@ -29,6 +35,8 @@

<% elsif params[:retired].present? %>

<%= t("proposals.index.retired_proposals") %>

+ <% elsif params[:selected].present? %> +

<%= t("proposals.index.selected_proposals") %>

<% end %>
@@ -69,7 +77,10 @@
- <%= render("shared/advanced_search", search_path: proposals_path(page: 1)) unless params[:retired].present? %> + <% unless params[:retired].present? || params[:selected].present? %> + <%= render "shared/advanced_search", + search_path: proposals_path(page: 1) %> + <% end %> <%= render "shared/order_links", i18n_namespace: "proposals.index" %> @@ -118,6 +129,7 @@ <%= render "popular" %> <% end %> <%= render "retired" %> + <%= render "selected" %> diff --git a/config/locales/en/activerecord.yml b/config/locales/en/activerecord.yml index 97c9431ca..142b8ecd4 100644 --- a/config/locales/en/activerecord.yml +++ b/config/locales/en/activerecord.yml @@ -187,6 +187,7 @@ en: title: "Title" question: "Question" description: "Description" + selected: "Mark as selected" terms_of_service: "Terms of service" user: login: "Email or username" diff --git a/config/locales/en/admin.yml b/config/locales/en/admin.yml index c03001722..4376979ba 100644 --- a/config/locales/en/admin.yml +++ b/config/locales/en/admin.yml @@ -1239,10 +1239,16 @@ en: title: Proposals id: ID author: Author + select: Select + selected: Selected milestones: Milestones no_proposals: There are no proposals. show: create_question: Add this proposal to a poll to be voted + form: + update: Update proposal + update: + notice: Proposal updated successfully hidden_proposals: index: filter: Filter diff --git a/config/locales/en/general.yml b/config/locales/en/general.yml index 820319ae6..021d120f1 100644 --- a/config/locales/en/general.yml +++ b/config/locales/en/general.yml @@ -376,6 +376,7 @@ en: error: "An error has occured. Please go to 'My account' page to manually disable recommendations for proposals" retired_proposals: Retired proposals retired_proposals_link: "Proposals retired by the author" + selected_proposals: Selected proposals retired_links: all: All duplicated: Duplicated diff --git a/config/locales/es/activerecord.yml b/config/locales/es/activerecord.yml index 13dd8783c..66a187114 100644 --- a/config/locales/es/activerecord.yml +++ b/config/locales/es/activerecord.yml @@ -187,6 +187,7 @@ es: title: "Título" question: "Pregunta" description: "Descripción" + selected: "Marcar como seleccionada" terms_of_service: "Términos de servicio" user: login: "Email o nombre de usuario" diff --git a/config/locales/es/admin.yml b/config/locales/es/admin.yml index 0e6a91fc0..7f63504aa 100644 --- a/config/locales/es/admin.yml +++ b/config/locales/es/admin.yml @@ -1239,9 +1239,15 @@ es: id: ID author: Autor milestones: Hitos + select: Seleccionar + selected: Seleccionada no_proposals: No hay propuestas. show: create_question: Añadir esta propuesta a una votación para ser votada + form: + update: Actualizar propuesta ciudadana + update: + notice: Propuesta actualizada correctamente hidden_proposals: index: filter: Filtro diff --git a/config/locales/es/general.yml b/config/locales/es/general.yml index deb858d95..76f88587a 100644 --- a/config/locales/es/general.yml +++ b/config/locales/es/general.yml @@ -376,6 +376,7 @@ es: error: "Ha ocurrido un error. Por favor dirígete al apartado 'Mi cuenta' para desactivar las recomendaciones manualmente" retired_proposals: Propuestas retiradas retired_proposals_link: "Propuestas retiradas por sus autores" + selected_proposals: Propuestas seleccionadas retired_links: all: Todas duplicated: Duplicadas diff --git a/config/routes/admin.rb b/config/routes/admin.rb index 917f1447c..1e67bcc5e 100644 --- a/config/routes/admin.rb +++ b/config/routes/admin.rb @@ -29,7 +29,8 @@ namespace :admin do end end - resources :proposals, only: [:index, :show] do + resources :proposals, only: [:index, :show, :update] do + member { patch :toggle_selection } resources :milestones, controller: "proposal_milestones" resources :progress_bars, except: :show, controller: "proposal_progress_bars" end diff --git a/spec/features/admin/proposals_spec.rb b/spec/features/admin/proposals_spec.rb index affc723f7..92685b139 100644 --- a/spec/features/admin/proposals_spec.rb +++ b/spec/features/admin/proposals_spec.rb @@ -10,6 +10,7 @@ feature "Admin proposals" do "admin_proposal_path" context "Index" do + scenario "Search" do create(:proposal, title: "Make Pluto a planet again") create(:proposal, title: "Build a monument to honour CONSUL developers") @@ -26,6 +27,29 @@ feature "Admin proposals" do expect(page).to have_content "Make Pluto a planet again" expect(page).not_to have_content "Build a monument" end + + scenario "Select a proposal", :js do + proposal = create(:proposal) + + visit admin_proposals_path + + within("#proposal_#{proposal.id}") { click_link "Select" } + + within("#proposal_#{proposal.id}") { expect(page).to have_link "Selected" } + expect(proposal.reload.selected?).to be true + end + + scenario "Unselect a proposal", :js do + proposal = create(:proposal, :selected) + + visit admin_proposals_path + + within("#proposal_#{proposal.id}") { click_link "Selected" } + + within("#proposal_#{proposal.id}") { expect(page).to have_link "Select" } + expect(proposal.reload.selected?).to be false + end + end context "Show" do @@ -55,5 +79,32 @@ feature "Admin proposals" do expect(page).to have_link "Add this proposal to a poll to be voted" end end + + scenario "Select a proposal" do + proposal = create(:proposal) + + visit admin_proposal_path(proposal) + + check "Mark as selected" + click_button "Update proposal" + + expect(page).to have_content "Proposal updated successfully" + expect(find_field("Mark as selected")).to be_checked + expect(proposal.reload.selected?).to be true + end + + scenario "Unselect a proposal" do + proposal = create(:proposal, :selected) + + visit admin_proposal_path(proposal) + + uncheck "Mark as selected" + click_button "Update proposal" + + expect(page).to have_content "Proposal updated successfully" + expect(find_field("Mark as selected")).not_to be_checked + expect(proposal.reload.selected?).to be false + end + end end diff --git a/spec/features/proposals_spec.rb b/spec/features/proposals_spec.rb index 5162dae30..74669a661 100644 --- a/spec/features/proposals_spec.rb +++ b/spec/features/proposals_spec.rb @@ -118,6 +118,25 @@ feature "Proposals" do end end + context "Index" do + scenario "Lists selected proposals" do + selected_proposal = create(:proposal, :selected) + unselected_proposal = create(:proposal) + + visit proposals_path + + expect(page).to have_selector("#proposals .proposal", count: 2) + expect(page).to have_content selected_proposal.title + expect(page).to have_content unselected_proposal.title + + click_link "Selected proposals" + + expect(page).to have_selector("#proposals .proposal", count: 1) + expect(page).to have_content selected_proposal.title + expect(page).not_to have_content unselected_proposal.title + end + end + scenario "Show" do proposal = create(:proposal)