Merge pull request #3907 from consul/polygon_geographies
Add polygon geographies to Budgets' map
This commit is contained in:
@@ -27,11 +27,12 @@
|
||||
});
|
||||
},
|
||||
synchronizeInputs: function() {
|
||||
var banners, inputs, processes, progress_bar;
|
||||
var banners, geozones, inputs, processes, progress_bar;
|
||||
progress_bar = "[name='progress_bar[percentage]']";
|
||||
processes = "[name='legislation_process[background_color]'], [name='legislation_process[font_color]']";
|
||||
banners = "[name='banner[background_color]'], [name='banner[font_color]']";
|
||||
inputs = $(progress_bar + ", " + processes + ", " + banners);
|
||||
geozones = "[name='geozone[color]']";
|
||||
inputs = $(progress_bar + ", " + processes + ", " + banners + ", " + geozones);
|
||||
inputs.on({
|
||||
input: function() {
|
||||
$("[name='" + this.name + "']").val($(this).val());
|
||||
|
||||
@@ -78,6 +78,7 @@
|
||||
}
|
||||
|
||||
App.Map.addInvestmentsMarkers(investmentsMarkers, createMarker);
|
||||
App.Map.addGeozones(map);
|
||||
},
|
||||
leafletMap: function(element) {
|
||||
var centerData, mapCenterLatLng;
|
||||
@@ -194,6 +195,28 @@
|
||||
map.attributionControl.setPrefix(App.Map.attributionPrefix());
|
||||
L.tileLayer(mapTilesProvider, { attribution: mapAttribution }).addTo(map);
|
||||
},
|
||||
addGeozones: function(map) {
|
||||
var geozones = $(map._container).data("geozones");
|
||||
|
||||
if (geozones) {
|
||||
geozones.forEach(function(geozone) {
|
||||
App.Map.addGeozone(geozone, map);
|
||||
});
|
||||
}
|
||||
},
|
||||
addGeozone: function(geozone, map) {
|
||||
var polygon = L.polygon(geozone.outline_points, {
|
||||
color: geozone.color,
|
||||
fillOpacity: 0.3,
|
||||
className: "map-polygon"
|
||||
});
|
||||
|
||||
if (geozone.headings !== undefined) {
|
||||
polygon.bindPopup(geozone.headings.join("<br>"));
|
||||
}
|
||||
|
||||
polygon.addTo(map);
|
||||
},
|
||||
openMarkerPopup: function(e) {
|
||||
var marker = e.target;
|
||||
$.ajax("/investments/" + marker.options.id + "/json_data", {
|
||||
|
||||
@@ -12,12 +12,19 @@
|
||||
<% end %>
|
||||
|
||||
<div class="small-12 medium-6">
|
||||
<% if @budget.show_money? %>
|
||||
<% if budget.show_money? %>
|
||||
<%= f.text_field :price, maxlength: 8 %>
|
||||
<% else %>
|
||||
<%= f.hidden_field :price, value: 0 %>
|
||||
<% end %>
|
||||
|
||||
<% if feature?(:map) %>
|
||||
<%= f.select :geozone_id,
|
||||
geozone_options,
|
||||
include_blank: t("geozones.none"),
|
||||
hint: t("admin.budget_headings.form.geozone_info") %>
|
||||
<% end %>
|
||||
|
||||
<% if heading.budget.approval_voting? %>
|
||||
<%= f.number_field :max_ballot_lines,
|
||||
hint: t("admin.budget_headings.form.max_ballot_lines_info") %>
|
||||
@@ -41,7 +48,7 @@
|
||||
</div>
|
||||
|
||||
<div class="clear">
|
||||
<% if respond_to?(:single_heading?) && single_heading? %>
|
||||
<% if single_heading? %>
|
||||
<%= f.submit t("admin.budgets_wizard.headings.continue"), class: "button success" %>
|
||||
<% else %>
|
||||
<%= f.submit t("admin.budget_headings.form.#{action}"), class: "button hollow" %>
|
||||
25
app/components/admin/budget_headings/form_component.rb
Normal file
25
app/components/admin/budget_headings/form_component.rb
Normal file
@@ -0,0 +1,25 @@
|
||||
class Admin::BudgetHeadings::FormComponent < ApplicationComponent
|
||||
include TranslatableFormHelper
|
||||
include GlobalizeHelper
|
||||
attr_reader :heading, :path, :action
|
||||
|
||||
def initialize(heading, path:, action:)
|
||||
@heading = heading
|
||||
@path = path
|
||||
@action = action
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def budget
|
||||
heading.budget
|
||||
end
|
||||
|
||||
def single_heading?
|
||||
helpers.respond_to?(:single_heading?) && helpers.single_heading?
|
||||
end
|
||||
|
||||
def geozone_options
|
||||
Geozone.all.map { |geozone| [geozone.name, geozone.id] }
|
||||
end
|
||||
end
|
||||
@@ -5,11 +5,12 @@
|
||||
<tr>
|
||||
<th><%= Budget::Heading.human_attribute_name(:name) %></th>
|
||||
<% if budget.show_money? %>
|
||||
<th class="text-center"><%= Budget::Heading.human_attribute_name(:price) %></th>
|
||||
<th><%= Budget::Heading.human_attribute_name(:price) %></th>
|
||||
<% end %>
|
||||
<% if budget.approval_voting? %>
|
||||
<th><%= Budget::Heading.human_attribute_name(:max_ballot_lines) %></th>
|
||||
<% end %>
|
||||
<th><%= Budget::Heading.human_attribute_name(:geozone_id) %></th>
|
||||
<th><%= t("admin.actions.actions") %></th>
|
||||
</tr>
|
||||
</thead>
|
||||
@@ -23,6 +24,9 @@
|
||||
<% if budget.approval_voting? %>
|
||||
<td><%= heading.max_ballot_lines %></td>
|
||||
<% end %>
|
||||
<td>
|
||||
<%= geozone_for(heading) %>
|
||||
</td>
|
||||
<td>
|
||||
<%= render Admin::TableActionsComponent.new(heading) %>
|
||||
</td>
|
||||
|
||||
@@ -14,4 +14,12 @@ class Admin::BudgetHeadings::HeadingsComponent < ApplicationComponent
|
||||
def budget
|
||||
@budget ||= group.budget
|
||||
end
|
||||
|
||||
def geozone_for(heading)
|
||||
if heading.geozone
|
||||
link_to heading.geozone.name, edit_admin_geozone_path(heading.geozone)
|
||||
else
|
||||
t("geozones.none")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,3 +1,3 @@
|
||||
<%= render Admin::BudgetsWizard::CreationStepComponent.new(heading, next_step_path) do %>
|
||||
<%= render "/admin/budget_headings/form", heading: heading, path: form_path, action: "create" %>
|
||||
<%= render Admin::BudgetHeadings::FormComponent.new(heading, path: form_path, action: "create") %>
|
||||
<% end %>
|
||||
|
||||
@@ -4,4 +4,4 @@
|
||||
|
||||
<%= render Admin::BudgetsWizard::CreationTimelineComponent.new("headings") %>
|
||||
|
||||
<%= render "/admin/budget_headings/form", heading: heading, path: form_path, action: "submit" %>
|
||||
<%= render Admin::BudgetHeadings::FormComponent.new(heading, path: form_path, action: "submit") %>
|
||||
|
||||
46
app/components/admin/geozones/form_component.html.erb
Normal file
46
app/components/admin/geozones/form_component.html.erb
Normal file
@@ -0,0 +1,46 @@
|
||||
<%= form_for [:admin, geozone] do |f| %>
|
||||
|
||||
<%= render "shared/errors", resource: geozone %>
|
||||
|
||||
<div class="small-12 large-8 column">
|
||||
<%= f.text_field :name %>
|
||||
</div>
|
||||
|
||||
<div class="clear">
|
||||
<div class="small-12 medium-6 large-4 column">
|
||||
<%= f.text_field :census_code, hint: t("admin.geozones.geozone.code_help") %>
|
||||
</div>
|
||||
|
||||
<div class="small-12 medium-6 large-4 column end">
|
||||
<%= f.text_field :external_code, hint: t("admin.geozones.geozone.code_help") %>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="small-12 large-8 column">
|
||||
<%= f.text_field :html_map_coordinates, hint: t("admin.geozones.geozone.coordinates_help") %>
|
||||
</div>
|
||||
|
||||
<div class="column">
|
||||
<%= f.text_area :geojson, rows: "10", hint: t("admin.geozones.geozone.geojson_help") %>
|
||||
</div>
|
||||
|
||||
<div class="small-12 large-3 column">
|
||||
<%= f.label :color, nil, for: "color_input", id: "color_input_label" %>
|
||||
<p class="help-text">
|
||||
<%= t("admin.geozones.geozone.color_help", format_help: t("admin.shared.color_help")) %>
|
||||
</p>
|
||||
<div class="row collapse">
|
||||
<div class="small-12 medium-6 column">
|
||||
<%= f.text_field :color, label: false, type: :color %>
|
||||
</div>
|
||||
<div class="small-12 medium-6 column">
|
||||
<%= f.text_field :color, label: false, id: "color_input" %>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="small-12 column">
|
||||
<%= f.submit(value: t("admin.geozones.edit.form.submit_button"),
|
||||
class: "button success") %>
|
||||
</div>
|
||||
<% end %>
|
||||
7
app/components/admin/geozones/form_component.rb
Normal file
7
app/components/admin/geozones/form_component.rb
Normal file
@@ -0,0 +1,7 @@
|
||||
class Admin::Geozones::FormComponent < ApplicationComponent
|
||||
attr_reader :geozone
|
||||
|
||||
def initialize(geozone)
|
||||
@geozone = geozone
|
||||
end
|
||||
end
|
||||
31
app/components/admin/geozones/index_component.html.erb
Normal file
31
app/components/admin/geozones/index_component.html.erb
Normal file
@@ -0,0 +1,31 @@
|
||||
<%= header do %>
|
||||
<%= link_to t("admin.geozones.index.create"), new_admin_geozone_path %>
|
||||
<% end %>
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th><%= t("admin.geozones.geozone.name") %></th>
|
||||
<th><%= t("admin.geozones.geozone.external_code") %></th>
|
||||
<th><%= t("admin.geozones.geozone.census_code") %></th>
|
||||
<th><%= t("admin.geozones.geozone.coordinates") %></th>
|
||||
<th><%= t("admin.geozones.geozone.geojson") %></th>
|
||||
<th><%= t("admin.actions.actions") %></th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
<% geozones.each do |geozone| %>
|
||||
<tr id="<%= dom_id(geozone) %>">
|
||||
<td><%= geozone.name %></td>
|
||||
<td><%= geozone.external_code %></td>
|
||||
<td><%= geozone.census_code %></td>
|
||||
<td><%= yes_no_text(geozone.html_map_coordinates.present?) %></td>
|
||||
<td><%= yes_no_text(geozone.geojson.present?) %></td>
|
||||
<td>
|
||||
<%= render Admin::TableActionsComponent.new(geozone) %>
|
||||
</td>
|
||||
</tr>
|
||||
<% end %>
|
||||
</tbody>
|
||||
</table>
|
||||
22
app/components/admin/geozones/index_component.rb
Normal file
22
app/components/admin/geozones/index_component.rb
Normal file
@@ -0,0 +1,22 @@
|
||||
class Admin::Geozones::IndexComponent < ApplicationComponent
|
||||
include Header
|
||||
attr_reader :geozones
|
||||
|
||||
def initialize(geozones)
|
||||
@geozones = geozones
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def title
|
||||
t("admin.geozones.index.title")
|
||||
end
|
||||
|
||||
def yes_no_text(condition)
|
||||
if condition
|
||||
t("shared.yes")
|
||||
else
|
||||
t("shared.no")
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -0,0 +1,3 @@
|
||||
<div class="budget-investments-map">
|
||||
<%= render_map(map_location, investments_coordinates: coordinates, geozones_data: geozones_data) %>
|
||||
</div>
|
||||
34
app/components/budgets/investments/map_component.rb
Normal file
34
app/components/budgets/investments/map_component.rb
Normal file
@@ -0,0 +1,34 @@
|
||||
class Budgets::Investments::MapComponent < ApplicationComponent
|
||||
attr_reader :heading, :investments
|
||||
delegate :render_map, to: :helpers
|
||||
|
||||
def initialize(investments, heading:)
|
||||
@investments = investments
|
||||
@heading = heading
|
||||
end
|
||||
|
||||
def render?
|
||||
map_location&.available?
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def map_location
|
||||
MapLocation.from_heading(heading) if heading.present?
|
||||
end
|
||||
|
||||
def coordinates
|
||||
MapLocation.where(investment: investments).map(&:json_data)
|
||||
end
|
||||
|
||||
def geozones_data
|
||||
return unless heading.geozone.present?
|
||||
|
||||
[
|
||||
{
|
||||
outline_points: heading.geozone.outline_points,
|
||||
color: heading.geozone.color
|
||||
}
|
||||
]
|
||||
end
|
||||
end
|
||||
@@ -1,4 +1,4 @@
|
||||
<div class="map inline">
|
||||
<div class="budgets-map">
|
||||
<h2><%= t("budgets.index.map") %></h2>
|
||||
<%= render_map(nil, investments_coordinates: coordinates) %>
|
||||
<%= render_map(nil, investments_coordinates: coordinates, geozones_data: geozones_data) %>
|
||||
</div>
|
||||
|
||||
@@ -13,8 +13,6 @@ class Budgets::MapComponent < ApplicationComponent
|
||||
private
|
||||
|
||||
def coordinates
|
||||
return unless budget.present?
|
||||
|
||||
if budget.publishing_prices_or_later? && budget.investments.selected.any?
|
||||
investments = budget.investments.selected
|
||||
else
|
||||
@@ -23,4 +21,16 @@ class Budgets::MapComponent < ApplicationComponent
|
||||
|
||||
MapLocation.where(investment_id: investments).map(&:json_data)
|
||||
end
|
||||
|
||||
def geozones_data
|
||||
budget.geozones.map do |geozone|
|
||||
{
|
||||
outline_points: geozone.outline_points,
|
||||
color: geozone.color,
|
||||
headings: budget.headings.where(geozone: geozone).map do |heading|
|
||||
link_to heading.name, budget_investments_path(budget, heading_id: heading.id)
|
||||
end
|
||||
}
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
class Shared::MapLocationComponent < ApplicationComponent
|
||||
attr_reader :investments_coordinates, :form
|
||||
attr_reader :investments_coordinates, :form, :geozones_data
|
||||
|
||||
def initialize(map_location, investments_coordinates: nil, form: nil)
|
||||
def initialize(map_location, investments_coordinates: nil, form: nil, geozones_data: nil)
|
||||
@map_location = map_location
|
||||
@investments_coordinates = investments_coordinates
|
||||
@form = form
|
||||
@geozones_data = geozones_data
|
||||
end
|
||||
|
||||
def map_location
|
||||
@@ -56,7 +57,8 @@ class Shared::MapLocationComponent < ApplicationComponent
|
||||
marker_remove_selector: "##{remove_marker_id}",
|
||||
marker_investments_coordinates: investments_coordinates,
|
||||
marker_latitude: map_location.latitude.presence,
|
||||
marker_longitude: map_location.longitude.presence
|
||||
marker_longitude: map_location.longitude.presence,
|
||||
geozones: geozones_data
|
||||
}.merge(input_selectors)
|
||||
end
|
||||
|
||||
|
||||
@@ -17,7 +17,7 @@ class Admin::GeozonesController < Admin::BaseController
|
||||
@geozone = Geozone.new(geozone_params)
|
||||
|
||||
if @geozone.save
|
||||
redirect_to admin_geozones_path
|
||||
redirect_to admin_geozones_path, notice: t("admin.geozones.create.notice")
|
||||
else
|
||||
render :new
|
||||
end
|
||||
@@ -25,7 +25,7 @@ class Admin::GeozonesController < Admin::BaseController
|
||||
|
||||
def update
|
||||
if @geozone.update(geozone_params)
|
||||
redirect_to admin_geozones_path
|
||||
redirect_to admin_geozones_path, notice: t("admin.geozones.update.notice")
|
||||
else
|
||||
render :edit
|
||||
end
|
||||
@@ -47,6 +47,6 @@ class Admin::GeozonesController < Admin::BaseController
|
||||
end
|
||||
|
||||
def allowed_params
|
||||
[:name, :external_code, :census_code, :html_map_coordinates]
|
||||
[:name, :external_code, :census_code, :html_map_coordinates, :geojson, :color]
|
||||
end
|
||||
end
|
||||
|
||||
@@ -20,7 +20,6 @@ module Budgets
|
||||
|
||||
before_action :load_ballot, only: [:index, :show]
|
||||
before_action :load_heading, only: [:index, :show]
|
||||
before_action :load_map, only: [:index]
|
||||
before_action :set_random_seed, only: :index
|
||||
before_action :load_categories, only: :index
|
||||
before_action :set_default_investment_filter, only: :index
|
||||
@@ -41,10 +40,9 @@ module Budgets
|
||||
|
||||
def index
|
||||
@investments = investments.page(params[:page]).per(PER_PAGE).for_render
|
||||
|
||||
@investment_ids = @investments.ids
|
||||
@investments_map_coordinates = MapLocation.where(investment: investments).map(&:json_data)
|
||||
|
||||
@investments_in_map = investments
|
||||
@tag_cloud = tag_cloud
|
||||
@remote_translations = detect_remote_translations(@investments)
|
||||
end
|
||||
@@ -179,9 +177,5 @@ module Budgets
|
||||
params[:filter] ||= "selected"
|
||||
end
|
||||
end
|
||||
|
||||
def load_map
|
||||
@map_location = MapLocation.from_heading(@heading) if @heading.present?
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -59,7 +59,7 @@ module Admin::BudgetHeadingsActions
|
||||
end
|
||||
|
||||
def allowed_params
|
||||
valid_attributes = [:price, :population, :allow_custom_content, :latitude, :longitude, :max_ballot_lines]
|
||||
valid_attributes = [:price, :population, :allow_custom_content, :latitude, :longitude, :max_ballot_lines, :geozone_id]
|
||||
|
||||
[*valid_attributes, translation_params(Budget::Heading)]
|
||||
end
|
||||
|
||||
@@ -34,6 +34,7 @@ class Budget < ApplicationRecord
|
||||
has_many :ballots, dependent: :destroy
|
||||
has_many :groups, dependent: :destroy
|
||||
has_many :headings, through: :groups
|
||||
has_many :geozones, through: :headings
|
||||
has_many :lines, through: :ballots, class_name: "Budget::Ballot::Line"
|
||||
has_many :phases, class_name: "Budget::Phase"
|
||||
has_many :budget_administrators, dependent: :destroy
|
||||
|
||||
@@ -22,6 +22,7 @@ class Budget
|
||||
end
|
||||
|
||||
belongs_to :group
|
||||
belongs_to :geozone
|
||||
|
||||
has_many :investments
|
||||
has_many :content_blocks
|
||||
|
||||
23
app/models/concerns/geojson_format_validator.rb
Normal file
23
app/models/concerns/geojson_format_validator.rb
Normal file
@@ -0,0 +1,23 @@
|
||||
class GeojsonFormatValidator < ActiveModel::EachValidator
|
||||
def validate_each(record, attribute, value)
|
||||
if value.present?
|
||||
geojson = parse_json(value)
|
||||
|
||||
unless geojson?(geojson)
|
||||
record.errors.add(attribute, :invalid)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def parse_json(geojson_data)
|
||||
JSON.parse(geojson_data) rescue nil
|
||||
end
|
||||
|
||||
def geojson?(geojson)
|
||||
return false unless geojson.is_a?(Hash)
|
||||
|
||||
geojson.dig("geometry", "coordinates").is_a?(Array)
|
||||
end
|
||||
end
|
||||
@@ -4,7 +4,9 @@ class Geozone < ApplicationRecord
|
||||
has_many :proposals
|
||||
has_many :debates
|
||||
has_many :users
|
||||
has_many :headings, class_name: "Budget::Heading", dependent: :nullify
|
||||
validates :name, presence: true
|
||||
validates :geojson, geojson_format: true
|
||||
|
||||
scope :public_for_api, -> { all }
|
||||
|
||||
@@ -17,4 +19,28 @@ class Geozone < ApplicationRecord
|
||||
association.klass.where(geozone: self).empty?
|
||||
end
|
||||
end
|
||||
|
||||
def outline_points
|
||||
normalized_coordinates.map { |longlat| [longlat.last, longlat.first] }
|
||||
end
|
||||
|
||||
private
|
||||
|
||||
def normalized_coordinates
|
||||
if geojson.present?
|
||||
if geojson.match(/"coordinates"\s*:\s*\[{4}/)
|
||||
coordinates.reduce([], :concat).reduce([], :concat)
|
||||
elsif geojson.match(/"coordinates"\s*:\s*\[{3}/)
|
||||
coordinates.reduce([], :concat)
|
||||
else
|
||||
coordinates
|
||||
end
|
||||
else
|
||||
[]
|
||||
end
|
||||
end
|
||||
|
||||
def coordinates
|
||||
JSON.parse(geojson)["geometry"]["coordinates"]
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
<%= render "header", action: "edit" %>
|
||||
|
||||
<%= render "form", heading: @heading, path: admin_budget_group_heading_path(@budget, @group, @heading), action: "submit" %>
|
||||
<%= render Admin::BudgetHeadings::FormComponent.new(
|
||||
@heading,
|
||||
path: admin_budget_group_heading_path(@budget, @group, @heading),
|
||||
action: "submit"
|
||||
) %>
|
||||
|
||||
@@ -1,3 +1,7 @@
|
||||
<%= render "header", action: "create" %>
|
||||
|
||||
<%= render "form", heading: @heading, path: admin_budget_group_headings_path(@budget, @group), action: "create" %>
|
||||
<%= render Admin::BudgetHeadings::FormComponent.new(
|
||||
@heading,
|
||||
path: admin_budget_group_headings_path(@budget, @group),
|
||||
action: "create"
|
||||
) %>
|
||||
|
||||
@@ -1,27 +0,0 @@
|
||||
<%= form_for [:admin, @geozone] do |f| %>
|
||||
|
||||
<%= render "shared/errors", resource: @geozone %>
|
||||
|
||||
<div class="small-12 large-8 column">
|
||||
<%= f.text_field :name %>
|
||||
</div>
|
||||
|
||||
<div class="clear">
|
||||
<div class="small-12 medium-6 large-4 column">
|
||||
<%= f.text_field :census_code, hint: t("admin.geozones.geozone.code_help") %>
|
||||
</div>
|
||||
|
||||
<div class="small-12 medium-6 large-4 column end">
|
||||
<%= f.text_field :external_code, hint: t("admin.geozones.geozone.code_help") %>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="small-12 large-8 column">
|
||||
<%= f.text_field :html_map_coordinates, hint: t("admin.geozones.geozone.coordinates_help") %>
|
||||
</div>
|
||||
|
||||
<div class="small-12 column">
|
||||
<%= f.submit(value: t("admin.geozones.edit.form.submit_button"),
|
||||
class: "button success") %>
|
||||
</div>
|
||||
<% end %>
|
||||
@@ -4,4 +4,4 @@
|
||||
<h2><%= t("admin.geozones.edit.editing") %></h2>
|
||||
</div>
|
||||
|
||||
<%= render "form" %>
|
||||
<%= render Admin::Geozones::FormComponent.new(@geozone) %>
|
||||
|
||||
@@ -1,30 +1 @@
|
||||
<%= link_to t("admin.geozones.index.create"),
|
||||
new_admin_geozone_path, class: "button float-right" %>
|
||||
|
||||
<h2 class="inline-block"><%= t("admin.geozones.index.title") %></h2>
|
||||
|
||||
<table>
|
||||
<thead>
|
||||
<tr>
|
||||
<th><%= t("admin.geozones.geozone.name") %></th>
|
||||
<th><%= t("admin.geozones.geozone.external_code") %></th>
|
||||
<th><%= t("admin.geozones.geozone.census_code") %></th>
|
||||
<th><%= t("admin.geozones.geozone.coordinates") %></th>
|
||||
<th><%= t("admin.actions.actions") %></th>
|
||||
</tr>
|
||||
</thead>
|
||||
|
||||
<tbody>
|
||||
<% @geozones.each do |geozone| %>
|
||||
<tr id="<%= dom_id(geozone) %>">
|
||||
<td><%= geozone.name %></td>
|
||||
<td><%= geozone.external_code %></td>
|
||||
<td><%= geozone.census_code %></td>
|
||||
<td class="break"><%= geozone.html_map_coordinates %></td>
|
||||
<td>
|
||||
<%= render Admin::TableActionsComponent.new(geozone) %>
|
||||
</td>
|
||||
</tr>
|
||||
<% end %>
|
||||
</tbody>
|
||||
</table>
|
||||
<%= render Admin::Geozones::IndexComponent.new(@geozones) %>
|
||||
|
||||
@@ -4,4 +4,4 @@
|
||||
<h2><%= t("admin.geozones.new.creating") %></h2>
|
||||
</div>
|
||||
|
||||
<%= render "form" %>
|
||||
<%= render Admin::Geozones::FormComponent.new(@geozone) %>
|
||||
|
||||
@@ -1,3 +0,0 @@
|
||||
<div class="map">
|
||||
<%= render_map(@map_location, investments_coordinates: @investments_map_coordinates) %>
|
||||
</div>
|
||||
@@ -22,10 +22,7 @@
|
||||
</div>
|
||||
|
||||
<%= render Budgets::Investments::ContentBlocksComponent.new(@heading) %>
|
||||
|
||||
<% if @map_location&.available? %>
|
||||
<%= render "budgets/investments/map" %>
|
||||
<% end %>
|
||||
<%= render Budgets::Investments::MapComponent.new(@investments_in_map, heading: @heading) %>
|
||||
<%= render "shared/tag_cloud", taggable: "Budget::Investment" %>
|
||||
<%= render "budgets/investments/categories" %>
|
||||
<%= render Budgets::Investments::FiltersComponent.new %>
|
||||
|
||||
@@ -201,7 +201,9 @@ en:
|
||||
geozone:
|
||||
name: Name
|
||||
external_code: "External code (optional)"
|
||||
color: "Color (optional)"
|
||||
census_code: "Census code (optional)"
|
||||
geojson: "GeoJSON data (optional)"
|
||||
html_map_coordinates: "HTML <map> Coordinates (optional)"
|
||||
milestone:
|
||||
status_id: "Current status (optional)"
|
||||
@@ -545,6 +547,10 @@ en:
|
||||
attributes:
|
||||
max_per_day:
|
||||
invalid: "You have reached the maximum number of private messages per day"
|
||||
geozone:
|
||||
attributes:
|
||||
geojson:
|
||||
invalid: "The GeoJSON provided does not follow the correct format. It must follow the \"Polygon\" or \"MultiPolygon\" type format."
|
||||
image:
|
||||
attributes:
|
||||
attachment:
|
||||
|
||||
@@ -198,6 +198,7 @@ en:
|
||||
success_notice: "Heading deleted successfully"
|
||||
unable_notice: "You cannot delete a Heading that has associated investments"
|
||||
form:
|
||||
geozone_info: "When a heading is associated with a geozone, the geozone will appear on this budget's map if the geozone includes GeoJSON data."
|
||||
max_ballot_lines_info: 'Maximum number of projects a user can vote on this heading during the "Voting projects" phase. Only for budgets using approval voting.'
|
||||
population_info: "Budget Heading population field is used for Statistic purposes at the end of the Budget to show for each Heading that represents an area with population what percentage voted. The field is optional so you can leave it empty if it doesn't apply."
|
||||
coordinates_info: "If latitude and longitude are provided, the investments page for this heading will include a map. This map will be centered using those coordinates."
|
||||
@@ -1391,8 +1392,13 @@ en:
|
||||
external_code: External code
|
||||
census_code: Census code
|
||||
code_help: Response code for this geozone on the census API
|
||||
coordinates: Coordinates
|
||||
color_help: "Color of the zone in a budget's map. %{format_help}"
|
||||
coordinates: Coordinates available
|
||||
coordinates_help: Coordinates that will generate a clickable area on an HTML image map
|
||||
geojson: GeoJSON available
|
||||
geojson_help: "Must follow the \"Polygon\" or \"MultiPolygon\" type format; on a budget's map, a polygon based on this data will appear when a heading is associated to this geozone"
|
||||
create:
|
||||
notice: "Geozone created successfully"
|
||||
edit:
|
||||
form:
|
||||
submit_button: Save changes
|
||||
@@ -1404,6 +1410,8 @@ en:
|
||||
delete:
|
||||
success: Geozone successfully deleted
|
||||
error: This geozone can't be deleted since there are elements attached to it
|
||||
update:
|
||||
notice: "Geozone updated successfully"
|
||||
signature_sheets:
|
||||
author: Author
|
||||
created_at: Creation date
|
||||
|
||||
@@ -200,8 +200,10 @@ es:
|
||||
description: "Descripción"
|
||||
geozone:
|
||||
name: Nombre
|
||||
color: "Color (opcional)"
|
||||
external_code: "Código externo (opcional)"
|
||||
census_code: "Código del censo (opcional)"
|
||||
geojson: "Datos GeoJSON (opcional)"
|
||||
html_map_coordinates: "Coordenadas HTML <map> (opcional)"
|
||||
milestone:
|
||||
status_id: "Estado actual (opcional)"
|
||||
@@ -545,6 +547,10 @@ es:
|
||||
attributes:
|
||||
max_per_day:
|
||||
invalid: "Has llegado al número máximo de mensajes privados por día"
|
||||
geozone:
|
||||
attributes:
|
||||
geojson:
|
||||
invalid: "Los datos GeoJSON proporcionados no tienen el formato correcto. Deben tener un tipo del formato \"Polygon\" o \"MultiPolygon\"."
|
||||
image:
|
||||
attributes:
|
||||
attachment:
|
||||
|
||||
@@ -198,6 +198,7 @@ es:
|
||||
success_notice: "Partida presupuestaria eliminada correctamente"
|
||||
unable_notice: "No se puede eliminar una partida presupuestaria con proyectos asociados"
|
||||
form:
|
||||
geozone_info: "Cuando se asocia una partida a una zona, la zona aparecerá en el mapa de este presupuesto si la zona incluye datos de GeoJSON."
|
||||
max_ballot_lines_info: 'Máximo número de proyectos que un usuario puede votar en esta partida durante la fase "Votación final". Solamente se aplica a presupuestos con votación por aprobación.'
|
||||
population_info: "El campo población de las partidas presupuestarias se usa con fines estadísticos únicamente, con el objetivo de mostrar el porcentaje de votos habidos en cada partida que represente un área con población. Es un campo opcional, así que puedes dejarlo en blanco si no aplica."
|
||||
coordinates_info: "Si se añaden los campos latitud y longitud, en la página de proyectos de esta partida aparecerá un mapa, que estará centrado en esas coordenadas."
|
||||
@@ -1391,8 +1392,13 @@ es:
|
||||
external_code: Código externo
|
||||
census_code: Código del censo
|
||||
code_help: Código de respuesta para esta zona en la API del censo
|
||||
coordinates: Coordenadas
|
||||
color_help: "Color con el que aparecerá esta zona en el mapa de un presupuesto. %{format_help}"
|
||||
coordinates: Coordenadas disponibles
|
||||
coordinates_help: Coordenadas que generarán una zona clicable en un mapa de imagen HTML
|
||||
geojson: GeoJSON disponible
|
||||
geojson_help: "Deben tener un tipo del formato \"Polygon\" o \"MultiPolygon\"; en el mapa de un presupuesto aparecerá un polígono basado en estos datos si una partida se asocia a esta geozona"
|
||||
create:
|
||||
notice: "Zona creada correctamente"
|
||||
edit:
|
||||
form:
|
||||
submit_button: Guardar cambios
|
||||
@@ -1404,6 +1410,8 @@ es:
|
||||
delete:
|
||||
success: Zona borrada correctamente
|
||||
error: No se puede borrar la zona porque ya tiene elementos asociados
|
||||
update:
|
||||
notice: "Zona actualizada correctamente"
|
||||
signature_sheets:
|
||||
author: Autor
|
||||
created_at: Fecha de creación
|
||||
|
||||
8
db/migrate/20181113184434_add_polygons_to_geozones.rb
Normal file
8
db/migrate/20181113184434_add_polygons_to_geozones.rb
Normal file
@@ -0,0 +1,8 @@
|
||||
class AddPolygonsToGeozones < ActiveRecord::Migration[5.0]
|
||||
def change
|
||||
change_table :geozones do |t|
|
||||
t.text :geojson
|
||||
t.string :color
|
||||
end
|
||||
end
|
||||
end
|
||||
5
db/migrate/20190109010131_add_geozone_to_headings.rb
Normal file
5
db/migrate/20190109010131_add_geozone_to_headings.rb
Normal file
@@ -0,0 +1,5 @@
|
||||
class AddGeozoneToHeadings < ActiveRecord::Migration[5.0]
|
||||
def change
|
||||
add_reference :budget_headings, :geozone, index: true, foreign_key: true
|
||||
end
|
||||
end
|
||||
@@ -238,9 +238,11 @@ ActiveRecord::Schema.define(version: 2023_05_23_090028) do
|
||||
t.boolean "allow_custom_content", default: false
|
||||
t.text "latitude"
|
||||
t.text "longitude"
|
||||
t.integer "geozone_id"
|
||||
t.integer "max_ballot_lines", default: 1
|
||||
t.datetime "created_at"
|
||||
t.datetime "updated_at"
|
||||
t.index ["geozone_id"], name: "index_budget_headings_on_geozone_id"
|
||||
t.index ["group_id"], name: "index_budget_headings_on_group_id"
|
||||
end
|
||||
|
||||
@@ -635,6 +637,8 @@ ActiveRecord::Schema.define(version: 2023_05_23_090028) do
|
||||
t.datetime "created_at", null: false
|
||||
t.datetime "updated_at", null: false
|
||||
t.string "census_code"
|
||||
t.text "geojson"
|
||||
t.string "color"
|
||||
end
|
||||
|
||||
create_table "geozones_polls", id: :serial, force: :cascade do |t|
|
||||
@@ -1775,6 +1779,7 @@ ActiveRecord::Schema.define(version: 2023_05_23_090028) do
|
||||
add_foreign_key "administrators", "users"
|
||||
add_foreign_key "budget_administrators", "administrators"
|
||||
add_foreign_key "budget_administrators", "budgets"
|
||||
add_foreign_key "budget_headings", "geozones"
|
||||
add_foreign_key "budget_investments", "communities"
|
||||
add_foreign_key "budget_valuators", "budgets"
|
||||
add_foreign_key "budget_valuators", "valuators"
|
||||
|
||||
32
spec/components/admin/budget_headings/form_component_spec.rb
Normal file
32
spec/components/admin/budget_headings/form_component_spec.rb
Normal file
@@ -0,0 +1,32 @@
|
||||
require "rails_helper"
|
||||
|
||||
describe Admin::BudgetHeadings::FormComponent do
|
||||
describe "geozone field" do
|
||||
let(:heading) { create(:budget_heading) }
|
||||
let(:component) { Admin::BudgetHeadings::FormComponent.new(heading, path: "/", action: nil) }
|
||||
before { Setting["feature.map"] = true }
|
||||
|
||||
it "is shown when the map feature is enabled" do
|
||||
render_inline component
|
||||
|
||||
expect(page).to have_select "Scope of operation"
|
||||
end
|
||||
|
||||
it "is not shown when the map feature is disabled" do
|
||||
Setting["feature.map"] = false
|
||||
|
||||
render_inline component
|
||||
|
||||
expect(page).not_to have_select "Scope of operation"
|
||||
end
|
||||
|
||||
it "includes all existing geozones plus an option for all city" do
|
||||
create(:geozone, name: "Under the sea")
|
||||
create(:geozone, name: "Above the skies")
|
||||
|
||||
render_inline component
|
||||
|
||||
expect(page).to have_select "Scope of operation", options: ["All city", "Under the sea", "Above the skies"]
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,6 +1,6 @@
|
||||
require "rails_helper"
|
||||
|
||||
describe Admin::BudgetHeadings::HeadingsComponent do
|
||||
describe Admin::BudgetHeadings::HeadingsComponent, controller: Admin::BaseController do
|
||||
it "includes group name in the message when there are no headings" do
|
||||
group = create(:budget_group, name: "Whole planet")
|
||||
|
||||
@@ -9,4 +9,22 @@ describe Admin::BudgetHeadings::HeadingsComponent do
|
||||
expect(page.text.strip).to eq "There are no headings in the Whole planet group."
|
||||
expect(page).to have_css "strong", exact_text: "Whole planet"
|
||||
end
|
||||
|
||||
describe "#geozone_for" do
|
||||
it "shows the geozone associated to the heading" do
|
||||
heading = create(:budget_heading, name: "Local", geozone: create(:geozone, name: "Here"))
|
||||
|
||||
render_inline Admin::BudgetHeadings::HeadingsComponent.new(heading.group.headings)
|
||||
|
||||
expect(page.find("tr", text: "Local")).to have_content "Here"
|
||||
end
|
||||
|
||||
it "shows a generic location for headings with no associated geozone" do
|
||||
heading = create(:budget_heading, name: "Universal", geozone: nil)
|
||||
|
||||
render_inline Admin::BudgetHeadings::HeadingsComponent.new(heading.group.headings)
|
||||
|
||||
expect(page.find("tr", text: "Universal")).to have_content "All city"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
23
spec/components/admin/geozones/index_component_spec.rb
Normal file
23
spec/components/admin/geozones/index_component_spec.rb
Normal file
@@ -0,0 +1,23 @@
|
||||
require "rails_helper"
|
||||
|
||||
describe Admin::Geozones::IndexComponent, controller: Admin::BaseController do
|
||||
describe "Coordinates description" do
|
||||
it "includes whether coordinates are defined or not" do
|
||||
geozones = [
|
||||
create(:geozone, :with_geojson, name: "GeoJSON", external_code: "1", census_code: "2"),
|
||||
create(:geozone, :with_html_coordinates, name: "HTML", external_code: "3", census_code: "4"),
|
||||
create(:geozone, :with_geojson, :with_html_coordinates, name: "With both", external_code: "6", census_code: "7"),
|
||||
create(:geozone, name: "With none", external_code: "8", census_code: "9")
|
||||
]
|
||||
|
||||
render_inline Admin::Geozones::IndexComponent.new(geozones)
|
||||
|
||||
expect(page).to have_table with_rows: [
|
||||
["GeoJSON", "1", "2", "No", "Yes", "Edit Delete"],
|
||||
["HTML", "3", "4", "Yes", "No", "Edit Delete"],
|
||||
["With both", "6", "7", "Yes", "Yes", "Edit Delete"],
|
||||
["With none", "8", "9", "No", "No", "Edit Delete"]
|
||||
]
|
||||
end
|
||||
end
|
||||
end
|
||||
@@ -1,20 +1,21 @@
|
||||
require "rails_helper"
|
||||
|
||||
describe Budgets::MapComponent do
|
||||
let(:budget) { build(:budget) }
|
||||
before { Setting["feature.map"] = true }
|
||||
let(:budget) { create(:budget, :accepting) }
|
||||
|
||||
describe "#render?" do
|
||||
let(:budget) { build(:budget) }
|
||||
|
||||
it "is rendered after the informing phase when the map feature is enabled" do
|
||||
Setting["feature.map"] = true
|
||||
budget.phase = "accepting"
|
||||
|
||||
render_inline Budgets::MapComponent.new(budget)
|
||||
|
||||
expect(page.first("div.map")).to have_content "located geographically"
|
||||
expect(page.find(".budgets-map")).to have_content "located geographically"
|
||||
end
|
||||
|
||||
it "is not rendered during the informing phase" do
|
||||
Setting["feature.map"] = true
|
||||
budget.phase = "informing"
|
||||
|
||||
render_inline Budgets::MapComponent.new(budget)
|
||||
@@ -31,4 +32,25 @@ describe Budgets::MapComponent do
|
||||
expect(page).not_to be_rendered
|
||||
end
|
||||
end
|
||||
|
||||
describe "#geozones_data" do
|
||||
it "renders data for the geozones associated with the budget" do
|
||||
create(:budget_heading, geozone: create(:geozone, color: "#0000ff"), budget: budget)
|
||||
create(:budget_heading, geozone: create(:geozone, color: "#ff0000"), budget: create(:budget))
|
||||
|
||||
render_inline Budgets::MapComponent.new(budget)
|
||||
|
||||
expect(page).to have_css "[data-geozones*='#0000ff']"
|
||||
expect(page).not_to have_css "[data-geozones*='#ff0000']"
|
||||
end
|
||||
|
||||
it "renders empty geozone data when there are no geozones" do
|
||||
create(:budget_heading, geozone: nil, budget: budget)
|
||||
create(:budget_heading, geozone: create(:geozone, color: "#ff0000"), budget: create(:budget))
|
||||
|
||||
render_inline Budgets::MapComponent.new(budget)
|
||||
|
||||
expect(page).to have_css "[data-geozones='[]']"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -8,10 +8,19 @@ FactoryBot.define do
|
||||
sequence(:name) { |n| "District #{n}" }
|
||||
sequence(:external_code, &:to_s)
|
||||
sequence(:census_code, &:to_s)
|
||||
color { "#0081aa" }
|
||||
|
||||
trait :in_census do
|
||||
census_code { "01" }
|
||||
end
|
||||
|
||||
trait :with_html_coordinates do
|
||||
html_map_coordinates { "30,139,45,153,77,148,107,165" }
|
||||
end
|
||||
|
||||
trait :with_geojson do
|
||||
geojson { '{ "geometry": { "type": "Polygon", "coordinates": [[-0.117,51.513],[-0.118,51.512],[-0.119,51.514]] } }' }
|
||||
end
|
||||
end
|
||||
|
||||
factory :banner do
|
||||
|
||||
@@ -12,6 +12,19 @@ describe Geozone do
|
||||
expect(geozone).not_to be_valid
|
||||
end
|
||||
|
||||
it "is valid without geojson" do
|
||||
geozone.geojson = nil
|
||||
expect(geozone).to be_valid
|
||||
end
|
||||
|
||||
it "is not valid with invalid geojson file format" do
|
||||
geozone.geojson = '{"geo\":{"type":"Incorrect key","coordinates": [
|
||||
[40.8792937308316, -3.9259027239257],
|
||||
[40.8788966596619, -3.9249047078766],
|
||||
[40.8789131852224, -3.9247799675785]]}}'
|
||||
expect(geozone).not_to be_valid
|
||||
end
|
||||
|
||||
describe "#safe_to_destroy?" do
|
||||
let(:geozone) { create(:geozone) }
|
||||
|
||||
@@ -33,5 +46,34 @@ describe Geozone do
|
||||
create(:debate, geozone: geozone)
|
||||
expect(geozone).not_to be_safe_to_destroy
|
||||
end
|
||||
|
||||
it "is false when already linked to a heading" do
|
||||
create(:budget_heading, geozone: geozone)
|
||||
expect(geozone).not_to be_safe_to_destroy
|
||||
end
|
||||
end
|
||||
|
||||
describe "#outline_points" do
|
||||
it "returns empty array when geojson is nil" do
|
||||
expect(geozone.outline_points).to eq([])
|
||||
end
|
||||
|
||||
it "returns coordinates array when geojson is not nil" do
|
||||
geozone = build(:geozone, geojson: '{
|
||||
"geometry": {
|
||||
"type": "Polygon",
|
||||
"coordinates": [
|
||||
[40.8792937308316, -3.9259027239257],
|
||||
[40.8788966596619, -3.9249047078766],
|
||||
[40.8789131852224, -3.9247799675785]
|
||||
]
|
||||
}
|
||||
}')
|
||||
|
||||
expect(geozone.outline_points).to eq(
|
||||
[[-3.9259027239257, 40.8792937308316],
|
||||
[-3.9249047078766, 40.8788966596619],
|
||||
[-3.9247799675785, 40.8789131852224]])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -112,19 +112,15 @@ describe "Budgets creation wizard", :admin do
|
||||
click_link "Finish"
|
||||
|
||||
within "section", text: "Heading groups" do
|
||||
within "section", text: "All city" do
|
||||
within_table "Headings in All city" do
|
||||
expect(page).to have_css "tbody tr", count: 1
|
||||
expect(page).to have_content "All city"
|
||||
end
|
||||
within_table "Headings in All city" do
|
||||
expect(page).to have_css "tbody tr", count: 1
|
||||
expect(page).to have_content "All city"
|
||||
end
|
||||
|
||||
within "section", text: "Districts" do
|
||||
within_table "Headings in Districts" do
|
||||
expect(page).to have_css "tbody tr", count: 2
|
||||
expect(page).to have_content "North"
|
||||
expect(page).to have_content "South"
|
||||
end
|
||||
within_table "Headings in Districts" do
|
||||
expect(page).to have_css "tbody tr", count: 2
|
||||
expect(page).to have_content "North"
|
||||
expect(page).to have_content "South"
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -27,6 +27,7 @@ describe "Admin geozones", :admin do
|
||||
|
||||
click_button "Save changes"
|
||||
|
||||
expect(page).to have_content "Geozone created successfully"
|
||||
expect(page).to have_content "Fancy District"
|
||||
|
||||
visit admin_geozones_path
|
||||
@@ -46,6 +47,8 @@ describe "Admin geozones", :admin do
|
||||
|
||||
click_button "Save changes"
|
||||
|
||||
expect(page).to have_content "Geozone updated successfully"
|
||||
|
||||
within("#geozone_#{geozone.id}") do
|
||||
expect(page).to have_content "New geozone name"
|
||||
expect(page).to have_content "333"
|
||||
@@ -64,6 +67,8 @@ describe "Admin geozones", :admin do
|
||||
|
||||
click_button "Save changes"
|
||||
|
||||
expect(page).to have_content "Geozone updated successfully"
|
||||
|
||||
within("#geozone_#{geozone.id}") do
|
||||
expect(page).to have_content "New geozone name"
|
||||
end
|
||||
@@ -102,4 +107,39 @@ describe "Admin geozones", :admin do
|
||||
expect(page).to have_content "Delete me!"
|
||||
end
|
||||
end
|
||||
|
||||
scenario "Show polygons when a heading is associated with a geozone" do
|
||||
Setting["feature.map"] = true
|
||||
|
||||
geojson = '{ "geometry": { "type": "Polygon", "coordinates": [[-0.1,51.5],[-0.2,51.4],[-0.3,51.6]] } }'
|
||||
geozone = create(:geozone, name: "Polygon me!")
|
||||
budget = create(:budget)
|
||||
group = create(:budget_group, budget: budget)
|
||||
heading = create(:budget_heading, name: "Area 51", group: group)
|
||||
|
||||
visit edit_admin_geozone_path(geozone)
|
||||
fill_in "GeoJSON data (optional)", with: geojson
|
||||
fill_in "Color (optional)", with: "#f5c211"
|
||||
click_button "Save changes"
|
||||
|
||||
expect(page).to have_content "Geozone updated successfully"
|
||||
|
||||
visit edit_admin_budget_group_heading_path(budget, group, heading)
|
||||
select "Polygon me!", from: "Scope of operation"
|
||||
|
||||
click_button "Save heading"
|
||||
|
||||
expect(page).to have_content "Heading updated successfully"
|
||||
|
||||
visit budget_path(budget)
|
||||
|
||||
expect(page).to have_css ".map-polygon[fill='#f5c211']"
|
||||
within(".map-location") { expect(page).not_to have_link "Area 51" }
|
||||
|
||||
find(".map-polygon").click
|
||||
|
||||
within ".map-location" do
|
||||
expect(page).to have_link "Area 51", href: budget_investments_path(budget, heading_id: heading.id)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1698,6 +1698,27 @@ describe "Budget Investments" do
|
||||
end
|
||||
end
|
||||
|
||||
scenario "Shows the polygon associated to the current heading" do
|
||||
triangle = '{ "geometry": { "type": "Polygon", "coordinates": [[-0.1,51.5],[-0.2,51.4],[-0.3,51.6]] } }'
|
||||
rectangle = '{ "geometry": { "type": "Polygon", "coordinates": [[-0.1,51.5],[-0.2,51.5],[-0.2,51.6],[-0.1,51.6]] } }'
|
||||
|
||||
park = create(:geozone, geojson: triangle, color: "#03ee03")
|
||||
square = create(:geozone, geojson: rectangle, color: "#ff04ff")
|
||||
|
||||
group = create(:budget_group)
|
||||
green_areas = create(:budget_heading, group: group, geozone: park, latitude: 51.5, longitude: -0.2)
|
||||
create(:budget_heading, group: group, geozone: square, latitude: 51.5, longitude: -0.2)
|
||||
|
||||
visit budget_investments_path(group.budget, heading_id: green_areas)
|
||||
|
||||
expect(page).to have_css ".map-polygon[fill='#03ee03']"
|
||||
expect(page).not_to have_css ".map-polygon[fill='#ff04ff']"
|
||||
|
||||
find(".map-polygon").click
|
||||
|
||||
expect(page).not_to have_css ".leaflet-popup"
|
||||
end
|
||||
|
||||
scenario "Shows all investments and not only the ones on the current page" do
|
||||
stub_const("#{Budgets::InvestmentsController}::PER_PAGE", 2)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user