Unify budget landing pages

There was a big difference between the current budget and a specific
budget landing page. This didn't really make too much sense. Also, it
was not possible to know how a draft participatory budget will look
before it was published.

By unifying those two views now they will look quite similar and it
will be possible for administrators to preview any draft budget and to
know how the budget will look like before actually publishing it.
This commit is contained in:
Julian Herrero
2020-04-30 10:55:55 +07:00
committed by Javi Martín
parent 6cfb862553
commit 7e3dd47d5a
13 changed files with 107 additions and 356 deletions

View File

@@ -0,0 +1,32 @@
<div class="budget-header">
<div class="row">
<div class="small-12 column">
<h1><%= budget.name %></h1>
<div class="description">
<%= auto_link_already_sanitized_html wysiwyg(budget.description) %>
</div>
<p>
<%= link_to t("budgets.index.section_header.help"), "#section_help" %>
</p>
</div>
</div>
</div>
<%= render Budgets::SubheaderComponent.new(budget) %>
<%= render Budgets::PhasesComponent.new(budget) %>
<div id="budget_info" class="budget-info">
<div class="row margin-top">
<div class="small-12 column">
<%= render Budgets::GroupsAndHeadingsComponent.new(budget) %>
<% unless budget.informing? %>
<div class="map inline">
<h3><%= t("budgets.index.map") %></h3>
<%= render_map(nil, "budgets", false, nil, coordinates) %>
</div>
<% end %>
</div>
</div>
</div>

View File

@@ -0,0 +1,22 @@
class Budgets::BudgetComponent < ApplicationComponent
delegate :wysiwyg, :auto_link_already_sanitized_html, :render_map, to: :helpers
attr_reader :budget
def initialize(budget)
@budget = budget
end
private
def coordinates
return unless budget.present?
if budget.publishing_prices_or_later? && budget.investments.selected.any?
investments = budget.investments.selected
else
investments = budget.investments
end
MapLocation.where(investment_id: investments).map(&:json_data)
end
end

View File

@@ -1,13 +1,11 @@
class BudgetsController < ApplicationController
include FeatureFlags
include BudgetsHelper
include InvestmentFilters
feature_flag :budgets
before_action :load_budget, only: :show
before_action :load_current_budget, only: :index
load_and_authorize_resource
before_action :set_default_investment_filter, only: :show
has_filters investment_filters, only: :show
respond_to :html, :js
@@ -17,7 +15,6 @@ class BudgetsController < ApplicationController
def index
@finished_budgets = @budgets.finished.order(created_at: :desc)
@budgets_coordinates = current_budget_map_locations
end
private
@@ -25,4 +22,8 @@ class BudgetsController < ApplicationController
def load_budget
@budget = Budget.find_by_slug_or_id! params[:id]
end
def load_current_budget
@budget = current_budget
end
end

View File

@@ -56,18 +56,6 @@ module BudgetsHelper
budget.published? || current_user&.administrator?
end
def current_budget_map_locations
return unless current_budget.present?
if current_budget.publishing_prices_or_later? && current_budget.investments.selected.any?
investments = current_budget.investments.selected
else
investments = current_budget.investments
end
MapLocation.where(investment_id: investments).map(&:json_data)
end
def display_calculate_winners_button?(budget)
budget.balloting_or_later?
end

View File

@@ -6,42 +6,12 @@
<%= render "shared/canonical", href: budgets_url %>
<% end %>
<% if current_budget.present? %>
<div class="budget-header">
<div class="row">
<div class="small-12 column">
<h1><%= current_budget.name %></h1>
<div class="description">
<%= auto_link_already_sanitized_html wysiwyg(current_budget.description) %>
</div>
<p>
<%= link_to t("budgets.index.section_header.help"), "#section_help" %>
</p>
</div>
</div>
</div>
<%= render Budgets::SubheaderComponent.new(current_budget) %>
<%= render Budgets::PhasesComponent.new(current_budget) %>
<div id="budget_info" class="budget-info">
<div class="row margin-top">
<div class="small-12 column">
<%= render Budgets::GroupsAndHeadingsComponent.new(current_budget) %>
<% unless current_budget.informing? %>
<div class="map inline">
<h3><%= t("budgets.index.map") %></h3>
<%= render_map(nil, "budgets", false, nil, @budgets_coordinates) %>
</div>
<% end %>
</div>
</div>
<% if @budget.present? %>
<%= render Budgets::BudgetComponent.new(@budget) %>
<% if @finished_budgets.present? %>
<%= render "finished", budgets: @finished_budgets %>
<% end %>
</div>
<% else %>
<div class="budget-header margin-bottom">
<div class="row">

View File

@@ -61,13 +61,13 @@
<% end %>
<p>
<%= link_to budget_path(@budget) do %>
<%= link_to budget_investments_path(@budget, heading_id: @heading) do %>
<small><%= t("budgets.results.investment_proyects") %></small>
<% end %><br>
<%= link_to budget_path(@budget, filter: "unfeasible") do %>
<%= link_to budget_investments_path(@budget, heading_id: @heading, filter: "unfeasible") do %>
<small><%= t("budgets.results.unfeasible_investment_proyects") %></small>
<% end %><br>
<%= link_to budget_path(@budget, filter: "unselected") do %>
<%= link_to budget_investments_path(@budget, heading_id: @heading, filter: "unselected") do %>
<small><%= t("budgets.results.not_selected_investment_proyects") %></small>
<% end %>
</p>

View File

@@ -1,75 +1,9 @@
<%= render Shared::BannerComponent.new("budgets") %>
<% provide :title do %><%= @budget.name %><% end %>
<% content_for :canonical do %>
<%= render "shared/canonical", href: budget_url(@budget, filter: @current_filter) %>
<% end %>
<div class="budget-header">
<div class="row">
<div class="small-12 column">
<%= back_link_to budgets_path %>
<h1><%= @budget.name %></h1>
<%= auto_link_already_sanitized_html wysiwyg(@budget.description) %>
</div>
</div>
</div>
<%= render Budgets::SubheaderComponent.new(@budget) %>
<div class="row margin">
<div class="small-12 medium-9 column">
<% if @current_filter == "unfeasible" %>
<h3 class="margin-bottom"><%= t("budgets.show.unfeasible_title") %></h3>
<% elsif @current_filter == "unselected" %>
<h3 class="margin-bottom"><%= t("budgets.show.unselected_title") %></h3>
<% end %>
<table class="table-fixed">
<thead>
<th><%= t("budgets.show.group") %></th>
</thead>
<tbody>
<% @budget.groups.each do |group| %>
<tr>
<td>
<% if group.single_heading_group? %>
<%= link_to group.name,
budget_investments_path(@budget,
heading_id: group.headings.first.id,
filter: @current_filter) %>
<% else %>
<%= link_to group.name,
budget_group_path(@budget, group,
filter: @current_filter) %>
<% end %>
<br>
</td>
</tr>
<% end %>
</tbody>
</table>
</div>
</div>
<% if @budget.balloting_or_later? %>
<% unless @current_filter == "unfeasible" %>
<div class="row">
<div class="small-12 column">
<small>
<%= link_to t("budgets.show.unfeasible"),
budget_path(@budget, filter: "unfeasible") %>
</small>
</div>
</div>
<% end %>
<% unless @current_filter == "unselected" %>
<div class="row">
<div class="small-12 column">
<small>
<%= link_to t("budgets.show.unselected"),
budget_path(@budget, filter: "unselected") %>
</small>
</div>
</div>
<% end %>
<% end %>
<%= render Budgets::BudgetComponent.new(@budget) %>
<%= render Budgets::FooterComponent.new %>

View File

@@ -178,11 +178,6 @@ en:
one: "You have selected <strong>1</strong> project out of <strong>%{limit}</strong>"
other: "You have selected <strong>%{count}</strong> projects out of <strong>%{limit}</strong>"
show:
group: Group
unfeasible_title: Unfeasible investments
unfeasible: See unfeasible investments
unselected_title: Investments not selected for balloting phase
unselected: See investments not selected for balloting phase
see_results: See results
results:
link: Results

View File

@@ -178,11 +178,6 @@ es:
one: "Has seleccionado <strong>1</strong> proyecto de <strong>%{limit}</strong>"
other: "Has seleccionado <strong>%{count}</strong> proyectos de <strong>%{limit}</strong>"
show:
group: Grupo
unfeasible_title: Proyectos de gasto inviables
unfeasible: Ver los proyectos inviables
unselected_title: Proyectos no seleccionados para la votación final
unselected: Ver los proyectos no seleccionados para la votación final
see_results: Ver resultados
results:
link: Resultados

View File

@@ -62,13 +62,6 @@ describe "Ballots" do
let!(:districts) { create(:budget_group, budget: budget, name: "Districts") }
context "Group and Heading Navigation" do
scenario "Groups" do
visit budget_path(budget)
expect(page).to have_link "City"
expect(page).to have_link "Districts"
end
scenario "Headings" do
create(:budget_heading, group: city, name: "Investments Type1")
create(:budget_heading, group: city, name: "Investments Type2")
@@ -76,17 +69,14 @@ describe "Ballots" do
create(:budget_heading, group: districts, name: "District 2")
visit budget_path(budget)
click_link "City"
within("#groups_and_headings") do
expect(page).to have_link "Investments Type1"
expect(page).to have_link "Investments Type2"
visit budget_path(budget)
click_link "Districts"
expect(page).to have_link "District 1"
expect(page).to have_link "District 2"
end
end
scenario "Investments" do
create(:budget_heading, group: city, name: "Under the city")
@@ -106,7 +96,6 @@ describe "Ballots" do
end
visit budget_path(budget)
click_link "City"
click_link "Above the city"
expect(page).to have_css(".budget-investment", count: 2)
@@ -114,8 +103,6 @@ describe "Ballots" do
expect(page).to have_content "Observatory"
visit budget_path(budget)
click_link "Districts"
click_link "District 1"
expect(page).to have_css(".budget-investment", count: 2)
@@ -123,22 +110,11 @@ describe "Ballots" do
expect(page).to have_content "Zero-emission zone"
visit budget_path(budget)
click_link "Districts"
click_link "District 2"
expect(page).to have_css(".budget-investment", count: 1)
expect(page).to have_content "Climbing wall"
end
scenario "Redirect to first heading if there is only one" do
city_heading = create(:budget_heading, group: city, name: "City")
city_investment = create(:budget_investment, :selected, heading: city_heading)
visit budget_path(budget)
click_link "City"
expect(page).to have_content city_investment.title
end
end
context "Adding and Removing Investments" do
@@ -146,10 +122,7 @@ describe "Ballots" do
create(:budget_investment, :selected, heading: new_york, price: 10000, title: "Bring back King Kong")
create(:budget_investment, :selected, heading: new_york, price: 20000, title: "Paint cabs black")
visit budget_path(budget)
click_link "States"
click_link "New York"
visit budget_investments_path(budget, heading_id: new_york)
add_to_ballot("Bring back King Kong")
expect(page).to have_css("#amount-spent", text: "€10,000")
@@ -176,9 +149,7 @@ describe "Ballots" do
scenario "Removing a investment", :js do
investment = create(:budget_investment, :selected, heading: new_york, price: 10000, balloters: [user])
visit budget_path(budget)
click_link "States"
click_link "New York"
visit budget_investments_path(budget, heading_id: new_york)
expect(page).to have_content investment.title
expect(page).to have_css("#amount-spent", text: "€10,000")
@@ -207,9 +178,7 @@ describe "Ballots" do
scenario "the Map shoud be visible before and after", :js do
create(:budget_investment, :selected, heading: new_york, price: 10000, title: "More bridges")
visit budget_path(budget)
click_link "States"
click_link "New York"
visit budget_investments_path(budget, heading_id: new_york)
within("#sidebar") do
expect(page).to have_content "OpenStreetMap"
@@ -244,8 +213,7 @@ describe "Ballots" do
create(:budget_investment, :selected, heading: district_heading1, price: 20000, title: "Average")
create(:budget_investment, :selected, heading: district_heading2, price: 30000, title: "Expensive")
visit budget_path(budget)
click_link "City"
visit budget_investments_path(budget, heading_id: city_heading)
add_to_ballot("Cheap")
@@ -257,9 +225,7 @@ describe "Ballots" do
expect(page).to have_content "€10,000"
end
visit budget_path(budget)
click_link "Districts"
click_link "District 1"
visit budget_investments_path(budget, heading_id: district_heading1)
expect(page).to have_css("#amount-spent", text: "€0")
expect(page).to have_css("#amount-spent", text: "€1,000,000")
@@ -277,8 +243,7 @@ describe "Ballots" do
expect(page).not_to have_content "€10,000"
end
visit budget_path(budget)
click_link "City"
visit budget_investments_path(budget, heading_id: city_heading)
expect(page).to have_css("#amount-spent", text: "€10,000")
expect(page).to have_css("#amount-available", text: "€9,990,000")
@@ -291,9 +256,7 @@ describe "Ballots" do
expect(page).not_to have_content "€20,000"
end
visit budget_path(budget)
click_link "Districts"
click_link "District 2"
visit budget_investments_path(budget, heading_id: district_heading2)
expect(page).to have_content("You have active votes in another heading: District 1")
end
@@ -318,14 +281,11 @@ describe "Ballots" do
scenario "Select my heading", :js do
create(:budget_investment, :selected, heading: california, title: "Green beach")
visit budget_path(budget)
click_link "States"
click_link "California"
visit budget_investments_path(budget, heading_id: california)
add_to_ballot("Green beach")
visit budget_path(budget)
click_link "States"
visit budget_group_path(budget, states)
expect(page).to have_content "California"
expect(page).to have_css("#budget_heading_#{california.id}.is-active")
@@ -346,8 +306,8 @@ describe "Ballots" do
add_to_ballot("Avengers Tower")
visit budget_path(budget)
click_link "States"
visit budget_group_path(budget, states)
expect(page).to have_css("#budget_heading_#{new_york.id}.is-active")
expect(page).not_to have_css("#budget_heading_#{california.id}.is-active")
end
@@ -364,16 +324,6 @@ describe "Ballots" do
end
context "Showing the ballot" do
scenario "Do not display heading name if there is only one heading in the group (example: group city)" do
group = create(:budget_group, budget: budget)
heading = create(:budget_heading, group: group)
visit budget_path(budget)
click_link group.name
# No need to click on the heading name
expect(page).to have_content("Investment projects with scope: #{heading.name}")
expect(page).to have_current_path(budget_investments_path(budget), ignore_query: true)
end
scenario "Displaying the correct group, heading, count & amount" do
group1 = create(:budget_group, budget: budget)
group2 = create(:budget_group, budget: budget)
@@ -543,9 +493,7 @@ describe "Ballots" do
investment = create(:budget_investment, heading: new_york, title: "WTF asdfasfd")
login_as(user)
visit budget_path(budget)
click_link states.name
click_link new_york.name
visit budget_investments_path(budget, heading_id: new_york)
expect(page).not_to have_css("#budget_investment_#{investment.id}")
end
@@ -554,9 +502,7 @@ describe "Ballots" do
investment = create(:budget_investment, :undecided, heading: new_york)
login_as(user)
visit budget_path(budget)
click_link states.name
click_link new_york.name
visit budget_investments_path(budget, heading_id: new_york)
within("#budget-investments") do
expect(page).not_to have_css("div.ballot")
@@ -682,9 +628,7 @@ describe "Ballots" do
in_browser(:user) do
login_as user
visit budget_path(budget)
click_link "States"
click_link "New York"
visit budget_investments_path(budget, heading_id: new_york)
expect(page).to have_css(".in-favor a")
end

View File

@@ -307,7 +307,7 @@ describe "Budgets" do
map_locations << { longitude: 40.123456789, latitude: "********" }
map_locations << { longitude: "**********", latitude: 3.12345678 }
budget_map_locations = map_locations.map do |map_location|
coordinates = map_locations.map do |map_location|
{
lat: map_location[:latitude],
long: map_location[:longitude],
@@ -317,8 +317,7 @@ describe "Budgets" do
}
end
allow_any_instance_of(BudgetsHelper).
to receive(:current_budget_map_locations).and_return(budget_map_locations)
allow_any_instance_of(Budgets::BudgetComponent).to receive(:coordinates).and_return(coordinates)
visit budgets_path
@@ -329,61 +328,32 @@ describe "Budgets" do
end
context "Show" do
scenario "List all groups" do
create(:budget_group, budget: budget)
create(:budget_group, budget: budget)
visit budget_path(budget)
budget.groups.each { |group| expect(page).to have_link(group.name) }
end
scenario "Links to unfeasible and selected if balloting or later" do
budget = create(:budget, :selecting)
group = create(:budget_group, budget: budget)
visit budget_path(budget)
expect(page).not_to have_link "See unfeasible investments"
expect(page).not_to have_link "See investments not selected for balloting phase"
click_link group.name
visit budget_group_path(budget, group)
expect(page).not_to have_link "See unfeasible investments"
expect(page).not_to have_link "See investments not selected for balloting phase"
budget.update!(phase: :publishing_prices)
visit budget_path(budget)
expect(page).not_to have_link "See unfeasible investments"
expect(page).not_to have_link "See investments not selected for balloting phase"
click_link group.name
visit budget_group_path(budget, group)
expect(page).not_to have_link "See unfeasible investments"
expect(page).not_to have_link "See investments not selected for balloting phase"
budget.update!(phase: :balloting)
visit budget_path(budget)
expect(page).to have_link "See unfeasible investments"
expect(page).to have_link "See investments not selected for balloting phase"
click_link group.name
visit budget_group_path(budget, group)
expect(page).to have_link "See unfeasible investments"
expect(page).to have_link "See investments not selected for balloting phase"
budget.update!(phase: :finished)
visit budget_path(budget)
expect(page).to have_link "See unfeasible investments"
expect(page).to have_link "See investments not selected for balloting phase"
click_link group.name
visit budget_group_path(budget, group)
expect(page).to have_link "See unfeasible investments"
expect(page).to have_link "See investments not selected for balloting phase"
@@ -399,8 +369,7 @@ describe "Budgets" do
heading3 = create(:budget_heading, group: group2, name: "Brooklyn")
heading4 = create(:budget_heading, group: group2, name: "Queens")
visit budget_path(budget)
click_link "New York"
visit budget_group_path(budget, group1)
expect(page).to have_css("#budget_heading_#{heading1.id}")
expect(page).to have_css("#budget_heading_#{heading2.id}")

View File

@@ -78,7 +78,7 @@ describe "Budget Investments" do
unfeasible_investment = create(:budget_investment, :unfeasible, heading: heading)
visit budget_path(budget)
click_link "Health"
click_link "More hospitals"
expect(page).to have_selector("#budget-investments .budget-investment", count: 3)
investments.each do |investment|
@@ -95,11 +95,9 @@ describe "Budget Investments" do
create(:budget_investment, heading: heading),
create(:budget_investment, heading: heading)]
visit budget_path(budget)
click_link "Health"
visit budget_investments_path(budget, heading_id: heading)
click_button "View mode"
click_link "List"
investments.each do |investment|
@@ -110,7 +108,6 @@ describe "Budget Investments" do
end
click_button "View mode"
click_link "Cards"
investments.each do |investment|
@@ -238,47 +235,6 @@ describe "Budget Investments" do
end
end
scenario "by unfeasibilty link for group with one heading" do
budget.update!(phase: :balloting)
group = create(:budget_group, name: "All City", budget: budget)
heading = create(:budget_heading, name: "Madrid", group: group)
visit budget_path(budget)
click_link "See unfeasible investments"
click_link "All City"
expected_path = budget_investments_path(budget, heading_id: heading.id, filter: "unfeasible")
expect(page).to have_current_path(expected_path)
end
scenario "by unfeasibilty link for group with many headings" do
budget.update!(phase: :balloting)
group = create(:budget_group, name: "Districts", budget: budget)
barajas = create(:budget_heading, name: "Barajas", group: group)
carabanchel = create(:budget_heading, name: "Carabanchel", group: group)
create(:budget_investment, :feasible, heading: barajas, title: "Terminal 5")
create(:budget_investment, :unfeasible, heading: barajas, title: "Seaport")
create(:budget_investment, :unfeasible, heading: carabanchel, title: "Airport")
visit budget_path(budget)
click_link "See unfeasible investments"
click_link "Districts"
click_link "Barajas"
within("#budget-investments") do
expect(page).to have_css(".budget-investment", count: 1)
expect(page).to have_content "Seaport"
expect(page).not_to have_content "Terminal 5"
expect(page).not_to have_content "Airport"
end
end
context "Results Phase" do
before { budget.update(phase: "finished", results_enabled: true) }
@@ -286,8 +242,7 @@ describe "Budget Investments" do
investment1 = create(:budget_investment, :winner, heading: heading)
investment2 = create(:budget_investment, :selected, heading: heading)
visit budget_path(budget)
click_link "Health"
visit budget_investments_path(budget, heading_id: heading)
within("#budget-investments") do
expect(page).to have_css(".budget-investment", count: 1)
@@ -297,7 +252,6 @@ describe "Budget Investments" do
visit budget_results_path(budget)
click_link "List of all investment projects"
click_link "Health"
within("#budget-investments") do
expect(page).to have_css(".budget-investment", count: 1)
@@ -312,7 +266,6 @@ describe "Budget Investments" do
visit budget_results_path(budget)
click_link "List of all unfeasible investment projects"
click_link "Health"
within("#budget-investments") do
expect(page).to have_css(".budget-investment", count: 1)
@@ -327,7 +280,6 @@ describe "Budget Investments" do
visit budget_results_path(budget)
click_link "List of all investment projects not selected for balloting"
click_link "Health"
within("#budget-investments") do
expect(page).to have_css(".budget-investment", count: 1)
@@ -1305,19 +1257,12 @@ describe "Budget Investments" do
create(:budget_investment, :selected, price: 100000, heading: new_york_heading, title: "NASA base")
login_as(user)
visit budget_path(budget)
click_link "Global Group"
# No need to click_link "Global Heading" because the link of a group with a single heading
# points to the list of investments directly
visit budget_investments_path(budget, heading: global_heading)
add_to_ballot("World T-Shirt")
add_to_ballot("Eco pens")
visit budget_path(budget)
click_link "Health"
click_link "Carabanchel"
visit budget_investments_path(budget, heading: carabanchel_heading)
add_to_ballot("Fireworks")
add_to_ballot("Bus pass")
@@ -1360,10 +1305,7 @@ describe "Budget Investments" do
create(:budget_investment, :selected, heading: heading_1, title: "Zero-emission zone")
login_as(user)
visit budget_path(budget)
click_link "Health"
click_link "Heading 1"
visit budget_investments_path(budget, heading_id: heading_1)
add_to_ballot("Zero-emission zone")
@@ -1413,45 +1355,6 @@ describe "Budget Investments" do
end
end
scenario "Shows unselected link for group with one heading" do
group = create(:budget_group, name: "All City", budget: budget)
heading = create(:budget_heading, name: "Madrid", group: group)
visit budget_path(budget)
click_link "See investments not selected for balloting phase"
click_link "All City"
expected_path = budget_investments_path(budget, heading_id: heading.id, filter: "unselected")
expect(page).to have_current_path(expected_path)
end
scenario "Shows unselected link for group with many headings" do
group = create(:budget_group, name: "Districts", budget: budget)
barajas = create(:budget_heading, name: "Barajas", group: group)
carabanchel = create(:budget_heading, name: "Carabanchel", group: group)
create(:budget_investment, :selected, heading: barajas, title: "Terminal 5")
create(:budget_investment, :unselected, heading: barajas, title: "Seaport")
create(:budget_investment, :unselected, heading: carabanchel, title: "Airport")
visit budget_path(budget)
click_link "See investments not selected for balloting phase"
click_link "Districts"
click_link "Barajas"
within("#budget-investments") do
expect(page).to have_css(".budget-investment", count: 1)
expect(page).to have_content "Seaport"
expect(page).not_to have_content "Terminal 5"
expect(page).not_to have_content "Airport"
end
end
scenario "Do not display vote button for unselected investments in index" do
investment = create(:budget_investment, :unselected, heading: heading)

View File

@@ -256,8 +256,7 @@ describe "Tags" do
end
login_as(admin) if budget.drafting?
visit budget_path(budget)
click_link group.name
visit budget_investments_path(budget, heading: heading.id)
within "#tag-cloud" do
click_link new_tag
@@ -305,8 +304,7 @@ describe "Tags" do
end
login_as(admin) if budget.drafting?
visit budget_path(budget)
click_link group.name
visit budget_investments_path(budget, heading: heading.id)
within "#categories" do
click_link tag_medio_ambiente.name