diff --git a/app/assets/stylesheets/admin.scss b/app/assets/stylesheets/admin.scss index e6bab74a3..cd79a951b 100644 --- a/app/assets/stylesheets/admin.scss +++ b/app/assets/stylesheets/admin.scss @@ -614,6 +614,16 @@ code { } } +.admin-content > header { + align-items: flex-start; + display: flex; + + a { + @include hollow-button; + margin-left: auto; + } +} + .admin-content .select-geozone, .admin-content .select-heading { diff --git a/app/assets/stylesheets/mixins.scss b/app/assets/stylesheets/mixins.scss index 060e31d83..875a1b913 100644 --- a/app/assets/stylesheets/mixins.scss +++ b/app/assets/stylesheets/mixins.scss @@ -198,3 +198,14 @@ transform: translateX(-50%); } } + +@mixin hollow-button($color: $link) { + @include button($style: hollow, $background: $color); + font-size: $base-font-size; + margin-bottom: 0; + + &:focus, + &:hover { + text-decoration: none; + } +} diff --git a/app/components/sdg_management/header.rb b/app/components/sdg_management/header.rb index 0a9370031..c9cb60d6e 100644 --- a/app/components/sdg_management/header.rb +++ b/app/components/sdg_management/header.rb @@ -1,11 +1,17 @@ module SDGManagement::Header extend ActiveSupport::Concern - def header + def header(&block) provide(:title) do "#{t("sdg_management.header.title")} - #{title}" end - tag.h2 title + tag.header do + if block_given? + tag.h2(title) + capture(&block) + else + tag.h2(title) + end + end end end diff --git a/app/components/sdg_management/local_targets/form_component.html.erb b/app/components/sdg_management/local_targets/form_component.html.erb new file mode 100644 index 000000000..df7c8a9ae --- /dev/null +++ b/app/components/sdg_management/local_targets/form_component.html.erb @@ -0,0 +1,41 @@ +<%= back_link_to sdg_management_local_targets_path %> + +<%= header %> + +<%= render "shared/globalize_locales", resource: local_target %> + +<%= translatable_form_for [:sdg_managment, local_target], url: form_url do |f| %> + <%= render "shared/errors", resource: local_target %> + +
+
+ <%= f.select :target_id, target_options %> +
+
+ +
+
+ <%= f.text_field :code, hint: t("sdg_management.local_targets.form.code") %> +
+
+ +
+ <%= f.translatable_fields do |translations_form| %> +
+ <%= translations_form.text_field :title %> +
+ +
+ <%= translations_form.text_area :description, + rows: 4, + hint: t("sdg_management.local_targets.form.description") %> +
+ <% end %> +
+ +
+
+ <%= f.submit class: "button" %> +
+
+<% end %> diff --git a/app/components/sdg_management/local_targets/form_component.rb b/app/components/sdg_management/local_targets/form_component.rb new file mode 100644 index 000000000..933e70bd1 --- /dev/null +++ b/app/components/sdg_management/local_targets/form_component.rb @@ -0,0 +1,44 @@ +class SDGManagement::LocalTargets::FormComponent < ApplicationComponent + delegate :back_link_to, to: :helpers + include SDGManagement::Header + include TranslatableFormHelper + include GlobalizeHelper + + attr_reader :local_target + + def initialize(local_target) + @local_target = local_target + end + + private + + def title + if local_target.persisted? + t("sdg_management.local_targets.edit.title") + else + t("sdg_management.local_targets.new.title") + end + end + + def form_url + if local_target.persisted? + sdg_management_local_target_path(local_target) + else + sdg_management_local_targets_path + end + end + + def target_options + grouped_targets = SDG::Goal.order(:code).map do |goal| + [ + code_and_title(goal), + goal.targets.sort.map { |target| [code_and_title(target), target.id] } + ] + end + grouped_options_for_select(grouped_targets, local_target.target_id) + end + + def code_and_title(resource) + "#{resource.code} #{resource.title}" + end +end diff --git a/app/components/sdg_management/local_targets/index_component.html.erb b/app/components/sdg_management/local_targets/index_component.html.erb new file mode 100644 index 000000000..0512c531b --- /dev/null +++ b/app/components/sdg_management/local_targets/index_component.html.erb @@ -0,0 +1,41 @@ +<%= header do %> + <%= link_to t("sdg_management.local_targets.index.new"), + new_sdg_management_local_target_path, + class: "new-link" %> +<% end %> + +<%= render SDGManagement::SubnavigationComponent.new(current: :local_targets) do %> + + + + + + + + + + + <% local_targets.group_by(&:target).map do |target, local_targets| %> + + + + + <% local_targets.each do |local_target| %> + + + + + + <% end %> + <% end %> + +
<%= attribute_name(:title) %><%= t("admin.actions.actions") %>
+ <%= target.code %> <%= target.title %> +
+ <%= local_target.code %> + + <%= local_target.title %> + + <%= actions(local_target) %> +
+<% end %> diff --git a/app/components/sdg_management/local_targets/index_component.rb b/app/components/sdg_management/local_targets/index_component.rb new file mode 100644 index 000000000..882836409 --- /dev/null +++ b/app/components/sdg_management/local_targets/index_component.rb @@ -0,0 +1,30 @@ +class SDGManagement::LocalTargets::IndexComponent < ApplicationComponent + include SDGManagement::Header + + attr_reader :local_targets + + def initialize(local_targets) + @local_targets = local_targets + end + + private + + def title + SDG::LocalTarget.model_name.human(count: 2).titleize + end + + def attribute_name(attribute) + SDG::LocalTarget.human_attribute_name(attribute) + end + + def header_id(object) + "#{dom_id(object)}_header" + end + + def actions(local_target) + render Admin::TableActionsComponent.new( + local_target, + edit_path: edit_sdg_management_local_target_path(local_target), + destroy_path: sdg_management_local_target_path(local_target)) + end +end diff --git a/app/components/sdg_management/menu_component.rb b/app/components/sdg_management/menu_component.rb index c594bd081..a168b0442 100644 --- a/app/components/sdg_management/menu_component.rb +++ b/app/components/sdg_management/menu_component.rb @@ -4,6 +4,6 @@ class SDGManagement::MenuComponent < ApplicationComponent private def sdg? - controller_name == "goals" || controller_name == "targets" + %w[goals targets local_targets].include?(controller_name) end end diff --git a/app/components/sdg_management/subnavigation_component.rb b/app/components/sdg_management/subnavigation_component.rb index 35d1a0fda..41096a618 100644 --- a/app/components/sdg_management/subnavigation_component.rb +++ b/app/components/sdg_management/subnavigation_component.rb @@ -8,7 +8,7 @@ class SDGManagement::SubnavigationComponent < ApplicationComponent private def sections - %i[goals targets] + %i[goals targets local_targets] end def link_to_section(section) diff --git a/app/controllers/sdg_management/local_targets_controller.rb b/app/controllers/sdg_management/local_targets_controller.rb new file mode 100644 index 000000000..d23fe06a7 --- /dev/null +++ b/app/controllers/sdg_management/local_targets_controller.rb @@ -0,0 +1,50 @@ +class SDGManagement::LocalTargetsController < SDGManagement::BaseController + include Translatable + + LocalTarget = ::SDG::LocalTarget + + def index + @local_targets = LocalTarget.all.sort + end + + def new + @local_target = LocalTarget.new + end + + def create + @local_target = LocalTarget.new(local_target_params) + + if @local_target.save + redirect_to sdg_management_local_targets_path, notice: t("sdg_management.local_targets.create.notice") + else + render :new + end + end + + def edit + @local_target = LocalTarget.find(params[:id]) + end + + def update + @local_target = LocalTarget.find(params[:id]) + + if @local_target.update(local_target_params) + redirect_to sdg_management_local_targets_path, notice: t("sdg_management.local_targets.update.notice") + else + render :edit + end + end + + def destroy + @local_target = LocalTarget.find(params[:id]) + @local_target.destroy! + redirect_to sdg_management_local_targets_path, notice: t("sdg_management.local_targets.destroy.notice") + end + + private + + def local_target_params + translations_attributes = translation_params(LocalTarget) + params.require(:sdg_local_target).permit(:code, :target_id, translations_attributes) + end +end diff --git a/app/models/concerns/sdg/relatable.rb b/app/models/concerns/sdg/relatable.rb index e85e1407c..9da20b0d5 100644 --- a/app/models/concerns/sdg/relatable.rb +++ b/app/models/concerns/sdg/relatable.rb @@ -4,7 +4,7 @@ module SDG::Relatable included do has_many :sdg_relations, as: :relatable, dependent: :destroy, class_name: "SDG::Relation" - %w[SDG::Goal SDG::Target].each do |sdg_type| + %w[SDG::Goal SDG::Target SDG::LocalTarget].each do |sdg_type| has_many sdg_type.constantize.table_name.to_sym, through: :sdg_relations, source: :related_sdg, diff --git a/app/models/sdg/local_target.rb b/app/models/sdg/local_target.rb new file mode 100644 index 000000000..8443e2a40 --- /dev/null +++ b/app/models/sdg/local_target.rb @@ -0,0 +1,37 @@ +class SDG::LocalTarget < ApplicationRecord + include Comparable + include SDG::Related + + delegate :goal, to: :target + + translates :title, touch: true + translates :description, touch: true + include Globalizable + + validates_translation :title, presence: true + validates_translation :description, presence: true + + validates :code, presence: true, uniqueness: true, + format: ->(local_target) { /\A#{local_target.target&.code}\.\d+/ } + validates :target, presence: true + + belongs_to :target + + def <=>(local_target) + return unless local_target.class == self.class + + [target, numeric_subcode] <=> [local_target.target, local_target.numeric_subcode] + end + + protected + + def numeric_subcode + subcode.to_i + end + + private + + def subcode + code.split(".").last + end +end diff --git a/app/models/sdg/target.rb b/app/models/sdg/target.rb index ad165e280..6ff87d155 100644 --- a/app/models/sdg/target.rb +++ b/app/models/sdg/target.rb @@ -6,6 +6,7 @@ class SDG::Target < ApplicationRecord validates :goal, presence: true belongs_to :goal + has_many :local_targets, dependent: :destroy def title I18n.t("sdg.goals.goal_#{goal.code}.targets.target_#{code_key}.title") diff --git a/app/views/sdg_management/local_targets/edit.html.erb b/app/views/sdg_management/local_targets/edit.html.erb new file mode 100644 index 000000000..07818dd63 --- /dev/null +++ b/app/views/sdg_management/local_targets/edit.html.erb @@ -0,0 +1 @@ +<%= render SDGManagement::LocalTargets::FormComponent.new(@local_target) %> diff --git a/app/views/sdg_management/local_targets/index.html.erb b/app/views/sdg_management/local_targets/index.html.erb new file mode 100644 index 000000000..de6e04103 --- /dev/null +++ b/app/views/sdg_management/local_targets/index.html.erb @@ -0,0 +1 @@ +<%= render SDGManagement::LocalTargets::IndexComponent.new(@local_targets) %> diff --git a/app/views/sdg_management/local_targets/new.html.erb b/app/views/sdg_management/local_targets/new.html.erb new file mode 100644 index 000000000..07818dd63 --- /dev/null +++ b/app/views/sdg_management/local_targets/new.html.erb @@ -0,0 +1 @@ +<%= render SDGManagement::LocalTargets::FormComponent.new(@local_target) %> diff --git a/config/locales/en/activerecord.yml b/config/locales/en/activerecord.yml index 5721fc5e5..73edfc440 100644 --- a/config/locales/en/activerecord.yml +++ b/config/locales/en/activerecord.yml @@ -75,6 +75,9 @@ en: sdg/goal: one: "goal" other: "goals" + sdg/local_target: + one: "local target" + other: "local targets" sdg/target: one: "target" other: "targets" @@ -318,6 +321,13 @@ en: code: "Code" title: "Title" description: "Description" + sdg/local_target: + code: "Code" + target_id: "Target" + title: "Title" + sdg/local_target/translation: + title: "Title" + description: "Description" sdg/target: code: "Code" title: "Title" @@ -571,6 +581,10 @@ en: attributes: locale: already_translated: Already translated resource + sdg/local_target: + attributes: + code: + invalid: "must start with the same code as its target followed by a dot and end with a number" messages: translations_too_short: Is mandatory to provide one translation at least record_invalid: "Validation failed: %{errors}" diff --git a/config/locales/en/general.yml b/config/locales/en/general.yml index 293e3b4e7..5a47cdb64 100644 --- a/config/locales/en/general.yml +++ b/config/locales/en/general.yml @@ -190,6 +190,7 @@ en: local_census_records/import: Local Census Records Import site_customization/content_block: content block site_customization/page: page + sdg/local_target: local target geozones: none: All city layouts: diff --git a/config/locales/en/sdg_management.yml b/config/locales/en/sdg_management.yml index d71b2e7be..1e075fd76 100644 --- a/config/locales/en/sdg_management.yml +++ b/config/locales/en/sdg_management.yml @@ -4,3 +4,19 @@ en: title: "SDG content" menu: sdg_content: "Goals and Targets" + local_targets: + create: + notice: "Local target created successfully" + destroy: + notice: "Local target deleted successfully" + edit: + title: "Edit local target" + form: + code: "Code must start with the selected target code followed by a dot" + description: "This description will be shown as help to users." + index: + new: "Create local target" + new: + title: "New local target" + update: + notice: "Local target updated successfully" diff --git a/config/locales/es/activerecord.yml b/config/locales/es/activerecord.yml index 4abe798c7..070ec9aa4 100644 --- a/config/locales/es/activerecord.yml +++ b/config/locales/es/activerecord.yml @@ -75,6 +75,9 @@ es: sdg/goal: one: "objetivo" other: "objetivos" + sdg/local_target: + one: "meta localizada" + other: "metas localizadas" sdg/target: one: "meta" other: "metas" @@ -315,6 +318,13 @@ es: code: "Código" title: "Título" description: "Descripción" + sdg/local_target: + code: "Código" + target_id: "Meta" + title: "Título" + sdg/local_target/translation: + title: "Título" + description: "Descripción" sdg/target: code: "Código" title: "Título" @@ -573,6 +583,10 @@ es: attributes: locale: already_translated: Recurso ya traducido + sdg/local_target: + attributes: + code: + invalid: "debe empezar con el código de su meta seguido de un punto y terminar con un número" messages: translations_too_short: El obligatorio proporcionar una traducción como mínimo record_invalid: "Error de validación: %{errors}" diff --git a/config/locales/es/general.yml b/config/locales/es/general.yml index 660cc7835..7f7b2b713 100644 --- a/config/locales/es/general.yml +++ b/config/locales/es/general.yml @@ -190,6 +190,7 @@ es: local_census_records/import: la importación de registros del censo local site_customization/content_block: el bloque site_customization/page: la página + sdg/local_target: la meta localizada geozones: none: Toda la ciudad layouts: diff --git a/config/locales/es/sdg_management.yml b/config/locales/es/sdg_management.yml index 58a378678..4ee4d8893 100644 --- a/config/locales/es/sdg_management.yml +++ b/config/locales/es/sdg_management.yml @@ -4,3 +4,19 @@ es: title: "Contenido ODS" menu: sdg_content: "Objetivos y Metas" + local_targets: + create: + notice: "Meta localizada creada correctamente" + destroy: + notice: "Meta localizada eliminada correctamente" + edit: + title: "Editar meta localizada" + form: + code: "El código debe comenzar por el código de la meta seleccionada seguida de un '.'" + description: "Este texto ser mostrará como ayuda para los usuarios." + index: + new: "Crear meta localizada" + new: + title: "Nueva meta localizada" + update: + notice: "Meta localizada asctualizada correctamente" diff --git a/config/routes/sdg_management.rb b/config/routes/sdg_management.rb index 50b0f45d5..cad7cbe66 100644 --- a/config/routes/sdg_management.rb +++ b/config/routes/sdg_management.rb @@ -3,4 +3,5 @@ namespace :sdg_management do resources :goals, only: [:index] resources :targets, only: [:index] + resources :local_targets, except: [:show] end diff --git a/db/dev_seeds/sdg.rb b/db/dev_seeds/sdg.rb index 01336730e..055f64e41 100644 --- a/db/dev_seeds/sdg.rb +++ b/db/dev_seeds/sdg.rb @@ -1,3 +1,32 @@ section "Creating Sustainable Development Goals" do load Rails.root.join("db", "sdg.rb") + + SDG::Target.sample(30).each do |target| + title = "Title for default locale" + description = "Description for default locale" + rand(2..3).times do |n| + local_target = SDG::LocalTarget.create!(code: "#{target.code}.#{n + 1}", + title: title, + description: description, + target: target) + random_locales.map do |locale| + Globalize.with_locale(locale) do + local_target.title = "Title for locale #{locale}" + local_target.description = "Description for locale #{locale}" + local_target.save! + end + end + end + end + + relatables = [Debate, Proposal, Poll, Legislation::Process, Budget::Investment] + relatables.map { |relatable| relatable.sample(5) }.flatten.each do |relatable| + Array(SDG::Goal.sample(rand(1..3))).each do |goal| + target = goal.targets.sample + local_target = target.local_targets.sample + relatable.sdg_goals << goal + relatable.sdg_targets << target + relatable.sdg_local_targets << local_target if local_target.present? + end + end end diff --git a/db/migrate/20201123124006_create_sdg_local_targets.rb b/db/migrate/20201123124006_create_sdg_local_targets.rb new file mode 100644 index 000000000..264a9cee9 --- /dev/null +++ b/db/migrate/20201123124006_create_sdg_local_targets.rb @@ -0,0 +1,22 @@ +class CreateSDGLocalTargets < ActiveRecord::Migration[5.2] + def change + create_table :sdg_local_targets do |t| + t.references :target + t.string :code + t.timestamps + + t.index :code, unique: true + end + + create_table :sdg_local_target_translations do |t| + t.bigint :sdg_local_target_id, null: false + t.string :locale, null: false + t.string :title + t.text :description + t.timestamps null: false + + t.index :locale + t.index :sdg_local_target_id + end + end +end diff --git a/db/schema.rb b/db/schema.rb index 5b1944278..601a3cdd3 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -10,7 +10,7 @@ # # It's strongly recommended that you check this file into your version control system. -ActiveRecord::Schema.define(version: 2020_11_17_200945) do +ActiveRecord::Schema.define(version: 2020_11_23_124006) do # These are extensions that must be enabled in order to support this database enable_extension "pg_trgm" @@ -1304,6 +1304,26 @@ ActiveRecord::Schema.define(version: 2020_11_17_200945) do t.index ["code"], name: "index_sdg_goals_on_code", unique: true end + create_table "sdg_local_target_translations", force: :cascade do |t| + t.bigint "sdg_local_target_id", null: false + t.string "locale", null: false + t.string "title" + t.text "description" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.index ["locale"], name: "index_sdg_local_target_translations_on_locale" + t.index ["sdg_local_target_id"], name: "index_sdg_local_target_translations_on_sdg_local_target_id" + end + + create_table "sdg_local_targets", force: :cascade do |t| + t.bigint "target_id" + t.string "code" + t.datetime "created_at", null: false + t.datetime "updated_at", null: false + t.index ["code"], name: "index_sdg_local_targets_on_code", unique: true + t.index ["target_id"], name: "index_sdg_local_targets_on_target_id" + end + create_table "sdg_relations", force: :cascade do |t| t.string "related_sdg_type" t.bigint "related_sdg_id" diff --git a/spec/factories/sdg.rb b/spec/factories/sdg.rb index 5e46622e8..9495a4114 100644 --- a/spec/factories/sdg.rb +++ b/spec/factories/sdg.rb @@ -6,4 +6,12 @@ FactoryBot.define do factory :sdg_target, class: "SDG::Target" do sequence(:code, 1) { |n| "#{n}.#{n}" } end + + factory :sdg_local_target, class: "SDG::LocalTarget" do + code { "1.1.1" } + sequence(:title) { |n| "Local Target #{n} title" } + sequence(:description) { |n| "Help for Local Target #{n}" } + + target { SDG::Target[code.rpartition(".").first] } + end end diff --git a/spec/models/sdg/local_target_spec.rb b/spec/models/sdg/local_target_spec.rb new file mode 100644 index 000000000..24c51c683 --- /dev/null +++ b/spec/models/sdg/local_target_spec.rb @@ -0,0 +1,77 @@ +require "rails_helper" + +describe SDG::LocalTarget do + describe "Concerns" do + it_behaves_like "globalizable", :sdg_local_target + end + + it "is valid" do + expect(build(:sdg_local_target)).to be_valid + end + + it "is not valid without a title" do + expect(build(:sdg_local_target, title: nil)).not_to be_valid + end + + it "is not valid without a description" do + expect(build(:sdg_local_target, description: nil)).not_to be_valid + end + + it "is not valid without a code" do + expect(build(:sdg_local_target, code: nil, target: SDG::Target[1.1])).not_to be_valid + end + + it "is not valid when code does not include associated target code" do + local_target = build(:sdg_local_target, code: "1.6.1", target: SDG::Target[1.1]) + + expect(local_target).not_to be_valid + expect(local_target.errors.full_messages).to include "Code must start with the same code as its target followed by a dot and end with a number" + end + + it "is not valid when local target code part is not a number" do + local_target = build(:sdg_local_target, code: "1.1.A", target: SDG::Target[1.1]) + + expect(local_target).not_to be_valid + expect(local_target.errors.full_messages).to include "Code must start with the same code as its target followed by a dot and end with a number" + end + + it "is not valid if code is not unique" do + create(:sdg_local_target, code: "1.1.1") + local_target = build(:sdg_local_target, code: "1.1.1") + + expect(local_target).not_to be_valid + expect(local_target.errors.full_messages).to include "Code has already been taken" + end + + it "is not valid without a target" do + expect(build(:sdg_local_target, target: nil)).not_to be_valid + end + + describe "#goal" do + it "returns the target goal" do + local_target = create(:sdg_local_target, code: "1.1.1") + + expect(local_target.goal).to eq(SDG::Goal[1]) + end + end + + describe "#<=>" do + let(:local_target,) { create(:sdg_local_target, code: "10.B.10") } + + it "compares using the target first" do + lesser_local_target = create(:sdg_local_target, code: "10.A.1") + greater_local_target = create(:sdg_local_target, code: "11.1.1") + + expect(local_target).to be > lesser_local_target + expect(local_target).to be < greater_local_target + end + + it "compares using the local target code when the target is the same" do + lesser_local_target = create(:sdg_local_target, code: "10.B.9") + greater_local_target = create(:sdg_local_target, code: "10.B.11") + + expect(local_target).to be > lesser_local_target + expect(local_target).to be < greater_local_target + end + end +end diff --git a/spec/models/sdg/relatable_spec.rb b/spec/models/sdg/relatable_spec.rb index 4b87971be..e6fd1b8d0 100644 --- a/spec/models/sdg/relatable_spec.rb +++ b/spec/models/sdg/relatable_spec.rb @@ -3,8 +3,10 @@ require "rails_helper" describe SDG::Relatable do let(:goal) { SDG::Goal[1] } let(:target) { SDG::Target["1.2"] } + let(:local_target) { create(:sdg_local_target, code: "1.2.1") } let(:another_goal) { SDG::Goal[2] } let(:another_target) { SDG::Target["2.3"] } + let(:another_local_target) { create(:sdg_local_target, code: "2.3.1") } let(:relatable) { create(:proposal) } @@ -44,12 +46,32 @@ describe SDG::Relatable do end end + describe "#sdg_local_targets" do + it "can assign local targets to a model" do + relatable.sdg_local_targets = [local_target, another_local_target] + + expect(SDG::Relation.count).to be 2 + expect(SDG::Relation.first.relatable).to eq relatable + expect(SDG::Relation.last.relatable).to eq relatable + expect(SDG::Relation.first.related_sdg).to eq local_target + expect(SDG::Relation.last.related_sdg).to eq another_local_target + end + + it "can obtain the list of local targets" do + relatable.sdg_local_targets = [local_target, another_local_target] + + expect(relatable.reload.sdg_local_targets).to match_array [local_target, another_local_target] + end + end + describe "#related_sdgs" do it "returns all related goals and targets" do relatable.sdg_goals = [goal, another_goal] relatable.sdg_targets = [target, another_target] + relatable.sdg_local_targets = [local_target, another_local_target] - expect(relatable.reload.related_sdgs).to match_array [goal, another_goal, target, another_target] + related_sdgs = [goal, another_goal, target, another_target, local_target, another_local_target] + expect(relatable.reload.related_sdgs).to match_array related_sdgs end end end diff --git a/spec/system/sdg_management/local_targets_spec.rb b/spec/system/sdg_management/local_targets_spec.rb new file mode 100644 index 000000000..437ec6c22 --- /dev/null +++ b/spec/system/sdg_management/local_targets_spec.rb @@ -0,0 +1,100 @@ +require "rails_helper" + +describe "Local Targets", :js do + before do + login_as(create(:administrator).user) + Setting["feature.sdg"] = true + end + + describe "Index" do + scenario "Visit the index" do + create(:sdg_local_target, code: "1.1.1", title: "Affordable food") + + visit sdg_management_goals_path + click_link "Local Targets" + + expect(page).to have_title "SDG content - Local Targets" + within("table tr", text: "Affordable food") do + expect(page).to have_link "Edit" + expect(page).to have_link "Delete" + end + expect(page).to have_link "Create local target" + end + + scenario "Show local targets grouped by target" do + target_1 = SDG::Target["1.1"] + target_1_local_target = create(:sdg_local_target, code: "1.1.1", target: target_1) + target_2 = SDG::Target["2.1"] + target_2_local_target = create(:sdg_local_target, code: "2.1.1", target: target_2) + + visit sdg_management_local_targets_path + + expect(target_1.title).to appear_before(target_1_local_target.title) + expect(target_1_local_target.title).to appear_before(target_2.title) + expect(target_2.title).to appear_before(target_2_local_target.title) + end + end + + describe "Create" do + scenario "Shows succesful notice when form is fullfilled correctly" do + visit new_sdg_management_local_target_path + + target = SDG::Target["1.1"] + select "#{target.code} #{target.title}", from: "Target" + fill_in "Code", with: "1.1.1" + fill_in "Title", with: "Local target title" + fill_in "Description", with: "Local target description" + click_button "Create local target" + + expect(page).to have_content("Local target created successfully") + expect(page).to have_content("1.1.1") + end + + scenario "Shows form errors when not valid" do + visit new_sdg_management_local_target_path + + target = SDG::Target["2.3"] + code_and_title = "#{target.code} #{target.title}" + select code_and_title, from: "Target" + click_button "Create local target" + + expect(page).to have_content("errors prevented this local target from being saved.") + expect(page).to have_select("Target", selected: code_and_title) + end + end + + describe "Update" do + let!(:local_target) { create(:sdg_local_target, code: "1.1.1") } + + scenario "Shows succesful notice when form is fullfilled correctly" do + visit edit_sdg_management_local_target_path(local_target) + + fill_in "Title", with: "Local target title update" + click_button "Update local target" + + expect(page).to have_content("Local target updated successfully") + expect(page).to have_content("Local target title update") + end + + scenario "Shows form errors when changes are not valid" do + visit edit_sdg_management_local_target_path(local_target) + + fill_in "Title", with: "" + click_button "Update local target" + + expect(page).to have_content("1 error prevented this local target from being saved.") + end + end + + describe "Destroy" do + scenario "Shows succesful notice when local target is destroyed successfully" do + create(:sdg_local_target, code: "1.1.1") + visit sdg_management_local_targets_path + + accept_confirm { click_link "Delete" } + + expect(page).to have_content("Local target deleted successfully") + expect(page).not_to have_content("1.1.1") + end + end +end