diff --git a/app/components/dossiers/invalid_ineligibilite_rules_component.rb b/app/components/dossiers/invalid_ineligibilite_rules_component.rb index 78047042f..3de971b68 100644 --- a/app/components/dossiers/invalid_ineligibilite_rules_component.rb +++ b/app/components/dossiers/invalid_ineligibilite_rules_component.rb @@ -1,18 +1,28 @@ # frozen_string_literal: true class Dossiers::InvalidIneligibiliteRulesComponent < ApplicationComponent - delegate :can_passer_en_construction?, to: :@dossier + delegate :can_passer_en_construction?, to: :dossier - def initialize(dossier:) + def initialize(dossier:, wrapped: true) @dossier = dossier @revision = dossier.revision + + @opened = !dossier.can_passer_en_construction? + @wrapped = wrapped end + private + + attr_reader :dossier + def render? - !can_passer_en_construction? + dossier.revision.ineligibilite_enabled? end def error_message - @dossier.revision.ineligibilite_message + dossier.revision.ineligibilite_message end + + def opened? = @opened + def wrapped? = @wrapped end diff --git a/app/components/dossiers/invalid_ineligibilite_rules_component/invalid_ineligibilite_rules_component.html.haml b/app/components/dossiers/invalid_ineligibilite_rules_component/invalid_ineligibilite_rules_component.html.haml index dd39925cd..061b44c06 100644 --- a/app/components/dossiers/invalid_ineligibilite_rules_component/invalid_ineligibilite_rules_component.html.haml +++ b/app/components/dossiers/invalid_ineligibilite_rules_component/invalid_ineligibilite_rules_component.html.haml @@ -1,8 +1,8 @@ -%div{ id: dom_id(@dossier, :ineligibilite_rules_broken), data: { controller: 'ineligibilite-rules-match', turbo_force: :server } } - %button.fr-sr-only{ aria: {controls: 'modal-eligibilite-rules-dialog' }, data: {'fr-opened': "false" } } +- modal_content = capture do + %button.fr-sr-only{ aria: { controls: 'modal-eligibilite-rules-dialog' }, data: { 'fr-opened': opened?.to_s } } show modal - %dialog.fr-modal{ "aria-labelledby" => "fr-modal-title-modal-1", role: "dialog", id: 'modal-eligibilite-rules-dialog', data: { 'ineligibilite-rules-match-target' => 'dialog' } } + %dialog.fr-modal{ "aria-labelledby" => "fr-modal-title-modal-1", role: "dialog", id: 'modal-eligibilite-rules-dialog', data: { 'turbo-permanent' => true } } .fr-container.fr-container--fluid.fr-container-md .fr-grid-row.fr-grid-row--center .fr-col-12.fr-col-md-8.fr-col-lg-6 @@ -14,3 +14,9 @@ %span.fr-icon-arrow-right-line.fr-icon--lg> = t('.modal.title') %p= error_message + +- if wrapped? + %div{ id: dom_id(@dossier, :ineligibilite_rules_broken) } + = modal_content +- else + = modal_content diff --git a/app/controllers/users/dossiers_controller.rb b/app/controllers/users/dossiers_controller.rb index 626cb0692..00160b984 100644 --- a/app/controllers/users/dossiers_controller.rb +++ b/app/controllers/users/dossiers_controller.rb @@ -280,9 +280,7 @@ module Users def update @dossier = dossier.en_construction? ? dossier.find_editing_fork(dossier.user) : dossier @dossier = dossier_with_champs(pj_template: false) - @can_passer_en_construction_was, @can_passer_en_construction_is = dossier.track_can_passer_en_construction do - update_dossier_and_compute_errors - end + update_dossier_and_compute_errors respond_to do |format| format.turbo_stream do diff --git a/app/javascript/controllers/ineligibilite_rules_match_controller.ts b/app/javascript/controllers/ineligibilite_rules_match_controller.ts deleted file mode 100644 index 5b47d79b5..000000000 --- a/app/javascript/controllers/ineligibilite_rules_match_controller.ts +++ /dev/null @@ -1,19 +0,0 @@ -import { ApplicationController } from './application_controller'; -declare interface modal { - disclose: () => void; -} -declare interface dsfr { - modal: modal; -} -declare const window: Window & - typeof globalThis & { dsfr: (elem: HTMLElement) => dsfr }; - -export class InvalidIneligibiliteRulesController extends ApplicationController { - static targets = ['dialog']; - - declare dialogTarget: HTMLElement; - - connect() { - setTimeout(() => window.dsfr(this.dialogTarget).modal.disclose(), 100); - } -} diff --git a/app/models/dossier.rb b/app/models/dossier.rb index 197702963..cad644dfd 100644 --- a/app/models/dossier.rb +++ b/app/models/dossier.rb @@ -1025,18 +1025,6 @@ class Dossier < ApplicationRecord procedure.accuse_lecture? && termine? end - def track_can_passer_en_construction - if !revision.ineligibilite_enabled - yield - [true, true] # without eligibilite rules, we never reach dossier.champs.visible?, don't cache anything - else - from = can_passer_en_construction? # with eligibilite rules, self.champ[x].visible is cached by passing thru conditions checks - yield - champs.map(&:reset_visible) # we must reset self.champs[x].visible?, because an update occurred and we should re-evaluate champs[x] visibility - [from, can_passer_en_construction?] - end - end - private def build_default_champs diff --git a/app/views/users/dossiers/update.turbo_stream.haml b/app/views/users/dossiers/update.turbo_stream.haml index 2cd14be47..0b7c13474 100644 --- a/app/views/users/dossiers/update.turbo_stream.haml +++ b/app/views/users/dossiers/update.turbo_stream.haml @@ -1,10 +1,7 @@ = render partial: 'shared/dossiers/update_champs', locals: { to_show: @to_show, to_hide: @to_hide, to_update: @to_update, dossier: @dossier } -- if !params.key?(:validate) - - if @can_passer_en_construction_was && !@can_passer_en_construction_is - = turbo_stream.append('contenu', render(Dossiers::InvalidIneligibiliteRulesComponent.new(dossier: @dossier))) - - else @ineligibilite_rules_is_computable - = turbo_stream.remove(dom_id(@dossier, :ineligibilite_rules_broken)) +- if params[:validate].present? && @dossier.revision.ineligibilite_enabled? + = turbo_stream.update dom_id(@dossier, :ineligibilite_rules_broken), render(Dossiers::InvalidIneligibiliteRulesComponent.new(dossier: @dossier, wrapped: false)) - if @update_contact_information = turbo_stream.update "contact_information", partial: 'shared/dossiers/update_contact_information', locals: { dossier: @dossier, procedure: @dossier.procedure } diff --git a/spec/controllers/users/dossiers_controller_spec.rb b/spec/controllers/users/dossiers_controller_spec.rb index 11ce0e20f..62970f9f5 100644 --- a/spec/controllers/users/dossiers_controller_spec.rb +++ b/spec/controllers/users/dossiers_controller_spec.rb @@ -775,9 +775,11 @@ describe Users::DossiersController, type: :controller do let(:types_de_champ_public) { [{ type: :text }, { type: :integer_number }] } let(:text_champ) { dossier.project_champs_public.first } let(:number_champ) { dossier.project_champs_public.last } + let(:validate) { "true" } let(:submit_payload) do { id: dossier.id, + validate:, dossier: { groupe_instructeur_id: dossier.groupe_instructeur_id, champs_public_attributes: { @@ -805,28 +807,36 @@ describe Users::DossiersController, type: :controller do end render_views - context 'when it switches from true to false' do + context 'when it becomes invalid' do let(:value) { must_be_greater_than + 1 } it 'raises popup' do subject dossier.reload expect(dossier.can_passer_en_construction?).to be_falsey - expect(assigns(:can_passer_en_construction_was)).to eq(true) - expect(assigns(:can_passer_en_construction_is)).to eq(false) - expect(response.body).to match(ActionView::RecordIdentifier.dom_id(dossier, :ineligibilite_rules_broken)) + expect(response.body).to match(/aria-controls='modal-eligibilite-rules-dialog'[^>]*data-fr-opened='true'/) end end - context 'when it stays true' do + context 'when it says valid' do let(:value) { must_be_greater_than - 1 } it 'does nothing' do subject dossier.reload expect(dossier.can_passer_en_construction?).to be_truthy - expect(assigns(:can_passer_en_construction_was)).to eq(true) - expect(assigns(:can_passer_en_construction_is)).to eq(true) - expect(response.body).not_to have_selector("##{ActionView::RecordIdentifier.dom_id(dossier, :ineligibilite_rules_broken)}") + expect(response.body).to match(/aria-controls='modal-eligibilite-rules-dialog'[^>]*data-fr-opened='false'/) + end + end + + context 'when not validating' do + let(:validate) { nil } + let(:value) { must_be_greater_than + 1 } + + it 'does not render invalid ineligible modal' do + subject + dossier.reload + expect(dossier.can_passer_en_construction?).to be_falsey + expect(response.body).not_to include("aria-controls='modal-eligibilite-rules-dialog'") end end end diff --git a/spec/system/users/dossier_ineligibilite_spec.rb b/spec/system/users/dossier_ineligibilite_spec.rb index ef52ae42c..fd7a32c1b 100644 --- a/spec/system/users/dossier_ineligibilite_spec.rb +++ b/spec/system/users/dossier_ineligibilite_spec.rb @@ -28,21 +28,21 @@ describe 'Dossier Inéligibilité', js: true do visit brouillon_dossier_path(dossier) # no error while dossier is empty expect(page).to have_selector(:button, text: "Déposer le dossier", disabled: false) - expect(page).not_to have_content("Vous ne pouvez pas déposer votre dossier") + expect(page).to have_selector("#modal-eligibilite-rules-dialog", visible: false) - # does raise error when dossier is filled with condition that does not match + # does nothing when dossier is filled with condition that does not match within "#champ-1" do find("label", text: "Non").click end expect(page).to have_selector(:button, text: "Déposer le dossier", disabled: false) - expect(page).not_to have_content("Vous ne pouvez pas déposer votre dossier") + expect(page).to have_selector("#modal-eligibilite-rules-dialog", visible: false) - # raise error when dossier is filled with condition that matches + # open modal when dossier is filled with condition that matches within "#champ-1" do find("label", text: "Oui").click end expect(page).to have_selector(:button, text: "Déposer le dossier", disabled: true) - expect(page).to have_content("Vous ne pouvez pas déposer votre dossier") + expect(page).to have_selector("#modal-eligibilite-rules-dialog", visible: true) # reload page and see error visit brouillon_dossier_path(dossier) @@ -51,6 +51,7 @@ describe 'Dossier Inéligibilité', js: true do # modal is closable, and we can change our dossier response to be eligible expect(page).to have_selector("#modal-eligibilite-rules-dialog", visible: true) + expect(page).to have_text("Vous ne pouvez pas déposer votre dossier") within("#modal-eligibilite-rules-dialog") { click_on "Fermer" } expect(page).to have_selector("#modal-eligibilite-rules-dialog", visible: false) @@ -78,7 +79,7 @@ describe 'Dossier Inéligibilité', js: true do visit brouillon_dossier_path(dossier) # no error while dossier is empty expect(page).to have_selector(:button, text: "Déposer le dossier", disabled: false) - expect(page).not_to have_content("Vous ne pouvez pas déposer votre dossier") + expect(page).to have_selector("#modal-eligibilite-rules-dialog", visible: false) # first condition matches (so ineligible), cannot submit dossier and error message is clear within "#champ-#{first_tdc.stable_id}" do @@ -148,14 +149,14 @@ describe 'Dossier Inéligibilité', js: true do visit brouillon_dossier_path(dossier) # no error while dossier is empty expect(page).to have_selector(:button, text: "Déposer le dossier", disabled: false) - expect(page).not_to have_content("Vous ne pouvez pas déposer votre dossier") + expect(page).to have_selector("#modal-eligibilite-rules-dialog", visible: false) # only one condition is matches, can submit dossier within "#champ-#{first_tdc.stable_id}" do find("label", text: "Oui").click end expect(page).to have_selector(:button, text: "Déposer le dossier", disabled: false) - expect(page).not_to have_content("Vous ne pouvez pas déposer votre dossier") + expect(page).to have_selector("#modal-eligibilite-rules-dialog", visible: false) # Now test dossier modification click_on "Déposer le dossier" @@ -196,7 +197,7 @@ describe 'Dossier Inéligibilité', js: true do scenario 'ineligibilite rules without validation on champ ensure to re-process cached champs.visible' do visit brouillon_dossier_path(dossier) expect(page).to have_selector(:button, text: "Déposer le dossier", disabled: false) - expect(page).not_to have_content("Vous ne pouvez pas déposer votre dossier") + expect(page).to have_selector("#modal-eligibilite-rules-dialog", visible: false) within "#champ-1" do find("label", text: "Non").click diff --git a/spec/views/shared/dossiers/_edit.html.haml_spec.rb b/spec/views/shared/dossiers/_edit.html.haml_spec.rb index 4271d129b..787e9cf07 100644 --- a/spec/views/shared/dossiers/_edit.html.haml_spec.rb +++ b/spec/views/shared/dossiers/_edit.html.haml_spec.rb @@ -160,6 +160,7 @@ describe 'shared/dossiers/edit', type: :view do before do allow(dossier).to receive(:can_passer_en_construction?).and_return(false) + allow(dossier.revision).to receive(:ineligibilite_enabled?).and_return(true) end it 'renders broken transitions rules dialog' do