diff --git a/app/assets/stylesheets/conditions_component.scss b/app/assets/stylesheets/conditions_component.scss index 152eb8c0a..4633531bd 100644 --- a/app/assets/stylesheets/conditions_component.scss +++ b/app/assets/stylesheets/conditions_component.scss @@ -3,6 +3,15 @@ .conditionnel { + .condition-error { + background: $background-red; + margin: ($default-spacer) (-$default-spacer); + + ul { + padding: $default-spacer; + } + } + .condition-table { table-layout: fixed; diff --git a/app/components/types_de_champ/conditions_component/conditions_component.html.haml b/app/components/types_de_champ/conditions_component/conditions_component.html.haml index f28edcfc2..871cb2e9b 100644 --- a/app/components/types_de_champ/conditions_component/conditions_component.html.haml +++ b/app/components/types_de_champ/conditions_component/conditions_component.html.haml @@ -5,6 +5,8 @@ %p.mr-2 Logique conditionnelle = logic_conditionnel_button + = render TypesDeChamp::ConditionsErrorsComponent.new(conditions: condition_per_row, upper_tdcs: @upper_tdcs) + - if @condition.present? %table.condition-table.mt-2.width-100 %thead diff --git a/app/components/types_de_champ/conditions_errors_component.rb b/app/components/types_de_champ/conditions_errors_component.rb new file mode 100644 index 000000000..c9d706145 --- /dev/null +++ b/app/components/types_de_champ/conditions_errors_component.rb @@ -0,0 +1,34 @@ +class TypesDeChamp::ConditionsErrorsComponent < ApplicationComponent + def initialize(conditions:, upper_tdcs:) + @conditions, @upper_tdcs = conditions, upper_tdcs + end + + private + + def errors + @conditions + .filter { |condition| condition.errors(@upper_tdcs.map(&:stable_id)).present? } + .map { |condition| row_error(Logic.split_condition(condition)) } + .uniq + .map { |message| tag.li(message) } + .then { |lis| tag.ul(lis.reduce(&:+)) } + end + + def row_error((left, operator_name, right)) + targeted_champ = @upper_tdcs.find { |tdc| tdc.stable_id == left.stable_id } + + if targeted_champ.nil? + "Un champ cible n'est plus disponible. Il est soit supprimé, soit déplacé en dessous de ce champ." + elsif left.type == :unmanaged + "Le champ « #{targeted_champ.libelle} » de type #{targeted_champ.type_champ} ne peut pas être utilisé comme champ cible." + else + "Le champ « #{targeted_champ.libelle} » est #{t(left.type, scope: '.type')}. Il ne peut pas être #{t(operator_name, scope: 'logic.operators').downcase} #{right.to_s.downcase}." + end + end + + def render? + @conditions + .filter { |condition| condition.errors(@upper_tdcs.map(&:stable_id)).present? } + .present? + end +end diff --git a/app/components/types_de_champ/conditions_errors_component/conditions_errors_component.fr.yml b/app/components/types_de_champ/conditions_errors_component/conditions_errors_component.fr.yml new file mode 100644 index 000000000..213de5ed8 --- /dev/null +++ b/app/components/types_de_champ/conditions_errors_component/conditions_errors_component.fr.yml @@ -0,0 +1,6 @@ +--- +fr: + type: + number: un nombre + string: un texte + boolean: soit oui, soit non diff --git a/app/components/types_de_champ/conditions_errors_component/conditions_errors_component.html.haml b/app/components/types_de_champ/conditions_errors_component/conditions_errors_component.html.haml new file mode 100644 index 000000000..b0e3dbce7 --- /dev/null +++ b/app/components/types_de_champ/conditions_errors_component/conditions_errors_component.html.haml @@ -0,0 +1,2 @@ +.condition-error + = errors diff --git a/spec/components/types_de_champ/conditions_errors_component_spec.rb b/spec/components/types_de_champ/conditions_errors_component_spec.rb new file mode 100644 index 000000000..4a9bc8532 --- /dev/null +++ b/spec/components/types_de_champ/conditions_errors_component_spec.rb @@ -0,0 +1,43 @@ +describe TypesDeChamp::ConditionsErrorsComponent, type: :component do + include Logic + + describe 'render' do + let(:conditions) { [] } + let(:upper_tdcs) { [] } + + before { render_inline(described_class.new(conditions: conditions, upper_tdcs: upper_tdcs)) } + + context 'when there are no condition' do + it { expect(page).to have_no_css('.condition-error') } + end + + context 'when the targeted_champ is not available' do + let(:tdc) { create(:type_de_champ_integer_number) } + let(:conditions) { [ds_eq(champ_value(tdc.stable_id), constant(1))] } + + it do + expect(page).to have_css('.condition-error') + expect(page).to have_content("Un champ cible n'est plus disponible") + end + end + + context 'when the targeted_champ is unmanaged' do + let(:tdc) { create(:type_de_champ_address) } + let(:upper_tdcs) { [tdc] } + let(:conditions) { [ds_eq(champ_value(tdc.stable_id), constant(1))] } + + it do + expect(page).to have_css('.condition-error') + expect(page).to have_content("ne peut pas être utilisé") + end + end + + context 'when the types mismatch' do + let(:tdc) { create(:type_de_champ_integer_number) } + let(:upper_tdcs) { [tdc] } + let(:conditions) { [ds_eq(champ_value(tdc.stable_id), constant('a'))] } + + it { expect(page).to have_content("Il ne peut pas être") } + end + end +end