class Conditions::ConditionsComponent < ApplicationComponent include Logic private def rows condition_per_row.map { |c| Logic.split_condition(c) } end def condition_per_row if [And, Or].include?(@condition.class) @condition.operands else [@condition].compact end end def far_left_tag(row_number) if row_number == 0 t('.display_if') elsif row_number == 1 select_tag( "#{input_prefix}[top_operator_name]", options_for_select(options_for_far_left_tag, @condition.class.name), class: 'fr-select' ) end end def options_for_far_left_tag [And, Or] .map(&:name) .map { |name| [t(name, scope: 'logic.operators'), name] } end def left_operand_tag(targeted_champ, row_index) # current_target can be invalid if # - its type has changed : number -> carto # - it has been removed # - it has been put lower in the form current_target_valid = targets_for_select.map(&:second).include?(targeted_champ.to_json) selected_target = current_target_valid ? targeted_champ.to_json : empty.to_json select_tag( input_name_for('targeted_champ'), options_for_select(targets_for_select, selected_target), onchange: "this.form.action = this.form.action + '/change_targeted_champ?row_index=#{row_index}'", id: input_id_for('targeted_champ', row_index), class: { 'fr-select': true, alert: !current_target_valid } ) end def targets_for_select empty_target_for_select + available_targets_for_select end def empty_target_for_select [[t('.select'), empty.to_json]] end def available_targets_for_select @source_tdcs .filter(&:conditionable?) .map { |tdc| [tdc.libelle, champ_value(tdc.stable_id).to_json] } end def operator_tag(operator_name, targeted_champ, row_index) operators_for_select = compatibles_operators_for_select(targeted_champ) current_operator_invalid = !operators_for_select.map(&:second).include?(operator_name) if current_operator_invalid operators_for_select = [[t('.select'), EmptyOperator.name]] + operators_for_select end select_tag( input_name_for('operator_name'), options_for_select(operators_for_select, selected: operator_name), id: input_id_for('operator_name', row_index), class: { 'fr-select': true, alert: current_operator_invalid } ) end def compatibles_operators_for_select(left) case left.type(@source_tdcs) when ChampValue::CHAMP_VALUE_TYPE.fetch(:boolean) [ [t('is', scope: 'logic'), Eq.name] ] when ChampValue::CHAMP_VALUE_TYPE.fetch(:empty) [ [t('is', scope: 'logic'), EmptyOperator.name] ] when ChampValue::CHAMP_VALUE_TYPE.fetch(:enum) [ [t('is', scope: 'logic'), Eq.name], [t('is_not', scope: 'logic'), NotEq.name] ] when ChampValue::CHAMP_VALUE_TYPE.fetch(:commune_enum), ChampValue::CHAMP_VALUE_TYPE.fetch(:epci_enum) [ [t(InDepartementOperator.name, scope: 'logic.operators'), InDepartementOperator.name], [t(NotInDepartementOperator.name, scope: 'logic.operators'), NotInDepartementOperator.name], [t(InRegionOperator.name, scope: 'logic.operators'), InRegionOperator.name], [t(NotInRegionOperator.name, scope: 'logic.operators'), NotInRegionOperator.name] ] when ChampValue::CHAMP_VALUE_TYPE.fetch(:departement_enum) [ [t('is', scope: 'logic'), Eq.name], [t('is_not', scope: 'logic'), NotEq.name], [t(InRegionOperator.name, scope: 'logic.operators'), InRegionOperator.name], [t(NotInRegionOperator.name, scope: 'logic.operators'), NotInRegionOperator.name] ] when ChampValue::CHAMP_VALUE_TYPE.fetch(:enums) [ [t(IncludeOperator.name, scope: 'logic.operators'), IncludeOperator.name], [t(ExcludeOperator.name, scope: 'logic.operators'), ExcludeOperator.name] ] when ChampValue::CHAMP_VALUE_TYPE.fetch(:number) [Eq, LessThan, GreaterThan, LessThanEq, GreaterThanEq] .map(&:name) .map { |name| [t(name, scope: 'logic.operators'), name] } else [] end end def right_operand_tag(left, right, row_index, operator_name) right_invalid = !current_right_valid?(left, right) case left.type(@source_tdcs) when :boolean booleans_for_select = [[t('utils.yes'), constant(true).to_json], [t('utils.no'), constant(false).to_json]] if right_invalid booleans_for_select = empty_target_for_select + booleans_for_select end select_tag( input_name_for('value'), options_for_select(booleans_for_select, right.to_json), id: input_id_for('value', row_index), class: { 'fr-select': true, alert: right_invalid } ) when :empty select_tag( input_name_for('value'), options_for_select(empty_target_for_select), id: input_id_for('value', row_index), class: 'fr-select' ) when :enum, :enums, :commune_enum, :epci_enum, :departement_enum enums_for_select = left.options(@source_tdcs, operator_name) if right_invalid enums_for_select = empty_target_for_select + enums_for_select end select_tag( input_name_for('value'), options_for_select(enums_for_select, right.value), id: input_id_for('value', row_index), class: { 'fr-select': true, alert: right_invalid } ) when :number text_field_tag( input_name_for('value'), right.value, required: true, id: input_id_for('value', row_index), class: { 'fr-select': true, alert: right_invalid } ) else text_field_tag(input_name_for('value'), '', id: input_id_for('value', row_index), class: 'fr-input') end end def current_right_valid?(left, right) Logic.compatible_type?(left, right, @source_tdcs) end def add_condition_tag tag.button( t('.add_condition'), formaction: add_condition_path, formnovalidate: true, class: 'fr-btn fr-btn--secondary fr-btn--sm fr-icon-add-circle-line fr-btn--icon-left' ) end def delete_condition_tag(row_index) tag.button( class: "fr-btn fr-btn--sm fr-btn--tertiary fr-icon-delete-line", title: t('.remove_a_row'), formaction: delete_condition_path(row_index), formmethod: 'delete', formnovalidate: true ) end def render? @condition.present? || available_targets_for_select.any? end def input_name_for(name) "#{input_prefix}[rows][][#{name}]" end end