fix(dossier): show ineligibilite message on update

This commit is contained in:
Colin Darie 2024-12-10 19:13:01 +01:00
parent eb682f1e64
commit 009e426c31
No known key found for this signature in database
GPG key ID: 4FB865FDBCA4BCC4
9 changed files with 55 additions and 63 deletions

View file

@ -1,18 +1,28 @@
# frozen_string_literal: true # frozen_string_literal: true
class Dossiers::InvalidIneligibiliteRulesComponent < ApplicationComponent 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 @dossier = dossier
@revision = dossier.revision @revision = dossier.revision
@opened = !dossier.can_passer_en_construction?
@wrapped = wrapped
end end
private
attr_reader :dossier
def render? def render?
!can_passer_en_construction? dossier.revision.ineligibilite_enabled?
end end
def error_message def error_message
@dossier.revision.ineligibilite_message dossier.revision.ineligibilite_message
end end
def opened? = @opened
def wrapped? = @wrapped
end end

View file

@ -1,8 +1,8 @@
%div{ id: dom_id(@dossier, :ineligibilite_rules_broken), data: { controller: 'ineligibilite-rules-match', turbo_force: :server } } - modal_content = capture do
%button.fr-sr-only{ aria: {controls: 'modal-eligibilite-rules-dialog' }, data: {'fr-opened': "false" } } %button.fr-sr-only{ aria: { controls: 'modal-eligibilite-rules-dialog' }, data: { 'fr-opened': opened?.to_s } }
show modal 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-container.fr-container--fluid.fr-container-md
.fr-grid-row.fr-grid-row--center .fr-grid-row.fr-grid-row--center
.fr-col-12.fr-col-md-8.fr-col-lg-6 .fr-col-12.fr-col-md-8.fr-col-lg-6
@ -14,3 +14,9 @@
%span.fr-icon-arrow-right-line.fr-icon--lg> %span.fr-icon-arrow-right-line.fr-icon--lg>
= t('.modal.title') = t('.modal.title')
%p= error_message %p= error_message
- if wrapped?
%div{ id: dom_id(@dossier, :ineligibilite_rules_broken) }
= modal_content
- else
= modal_content

View file

@ -280,9 +280,7 @@ module Users
def update def update
@dossier = dossier.en_construction? ? dossier.find_editing_fork(dossier.user) : dossier @dossier = dossier.en_construction? ? dossier.find_editing_fork(dossier.user) : dossier
@dossier = dossier_with_champs(pj_template: false) @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
update_dossier_and_compute_errors
end
respond_to do |format| respond_to do |format|
format.turbo_stream do format.turbo_stream do

View file

@ -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);
}
}

View file

@ -1025,18 +1025,6 @@ class Dossier < ApplicationRecord
procedure.accuse_lecture? && termine? procedure.accuse_lecture? && termine?
end 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 private
def build_default_champs def build_default_champs

View file

@ -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 } = 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 params[:validate].present? && @dossier.revision.ineligibilite_enabled?
- if @can_passer_en_construction_was && !@can_passer_en_construction_is = turbo_stream.update dom_id(@dossier, :ineligibilite_rules_broken), render(Dossiers::InvalidIneligibiliteRulesComponent.new(dossier: @dossier, wrapped: false))
= 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 @update_contact_information - if @update_contact_information
= turbo_stream.update "contact_information", partial: 'shared/dossiers/update_contact_information', locals: { dossier: @dossier, procedure: @dossier.procedure } = turbo_stream.update "contact_information", partial: 'shared/dossiers/update_contact_information', locals: { dossier: @dossier, procedure: @dossier.procedure }

View file

@ -775,9 +775,11 @@ describe Users::DossiersController, type: :controller do
let(:types_de_champ_public) { [{ type: :text }, { type: :integer_number }] } let(:types_de_champ_public) { [{ type: :text }, { type: :integer_number }] }
let(:text_champ) { dossier.project_champs_public.first } let(:text_champ) { dossier.project_champs_public.first }
let(:number_champ) { dossier.project_champs_public.last } let(:number_champ) { dossier.project_champs_public.last }
let(:validate) { "true" }
let(:submit_payload) do let(:submit_payload) do
{ {
id: dossier.id, id: dossier.id,
validate:,
dossier: { dossier: {
groupe_instructeur_id: dossier.groupe_instructeur_id, groupe_instructeur_id: dossier.groupe_instructeur_id,
champs_public_attributes: { champs_public_attributes: {
@ -805,28 +807,36 @@ describe Users::DossiersController, type: :controller do
end end
render_views render_views
context 'when it switches from true to false' do context 'when it becomes invalid' do
let(:value) { must_be_greater_than + 1 } let(:value) { must_be_greater_than + 1 }
it 'raises popup' do it 'raises popup' do
subject subject
dossier.reload dossier.reload
expect(dossier.can_passer_en_construction?).to be_falsey expect(dossier.can_passer_en_construction?).to be_falsey
expect(assigns(:can_passer_en_construction_was)).to eq(true) expect(response.body).to match(/aria-controls='modal-eligibilite-rules-dialog'[^>]*data-fr-opened='true'/)
expect(assigns(:can_passer_en_construction_is)).to eq(false)
expect(response.body).to match(ActionView::RecordIdentifier.dom_id(dossier, :ineligibilite_rules_broken))
end end
end end
context 'when it stays true' do context 'when it says valid' do
let(:value) { must_be_greater_than - 1 } let(:value) { must_be_greater_than - 1 }
it 'does nothing' do it 'does nothing' do
subject subject
dossier.reload dossier.reload
expect(dossier.can_passer_en_construction?).to be_truthy expect(dossier.can_passer_en_construction?).to be_truthy
expect(assigns(:can_passer_en_construction_was)).to eq(true) expect(response.body).to match(/aria-controls='modal-eligibilite-rules-dialog'[^>]*data-fr-opened='false'/)
expect(assigns(:can_passer_en_construction_is)).to eq(true) end
expect(response.body).not_to have_selector("##{ActionView::RecordIdentifier.dom_id(dossier, :ineligibilite_rules_broken)}") 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 end
end end

View file

@ -28,21 +28,21 @@ describe 'Dossier Inéligibilité', js: true do
visit brouillon_dossier_path(dossier) visit brouillon_dossier_path(dossier)
# no error while dossier is empty # no error while dossier is empty
expect(page).to have_selector(:button, text: "Déposer le dossier", disabled: false) 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 within "#champ-1" do
find("label", text: "Non").click find("label", text: "Non").click
end end
expect(page).to have_selector(:button, text: "Déposer le dossier", disabled: false) 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 within "#champ-1" do
find("label", text: "Oui").click find("label", text: "Oui").click
end end
expect(page).to have_selector(:button, text: "Déposer le dossier", disabled: true) 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 # reload page and see error
visit brouillon_dossier_path(dossier) 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 # 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_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" } within("#modal-eligibilite-rules-dialog") { click_on "Fermer" }
expect(page).to have_selector("#modal-eligibilite-rules-dialog", visible: false) 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) visit brouillon_dossier_path(dossier)
# no error while dossier is empty # no error while dossier is empty
expect(page).to have_selector(:button, text: "Déposer le dossier", disabled: false) 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 # first condition matches (so ineligible), cannot submit dossier and error message is clear
within "#champ-#{first_tdc.stable_id}" do within "#champ-#{first_tdc.stable_id}" do
@ -148,14 +149,14 @@ describe 'Dossier Inéligibilité', js: true do
visit brouillon_dossier_path(dossier) visit brouillon_dossier_path(dossier)
# no error while dossier is empty # no error while dossier is empty
expect(page).to have_selector(:button, text: "Déposer le dossier", disabled: false) 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 # only one condition is matches, can submit dossier
within "#champ-#{first_tdc.stable_id}" do within "#champ-#{first_tdc.stable_id}" do
find("label", text: "Oui").click find("label", text: "Oui").click
end end
expect(page).to have_selector(:button, text: "Déposer le dossier", disabled: false) 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 # Now test dossier modification
click_on "Déposer le dossier" 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 scenario 'ineligibilite rules without validation on champ ensure to re-process cached champs.visible' do
visit brouillon_dossier_path(dossier) visit brouillon_dossier_path(dossier)
expect(page).to have_selector(:button, text: "Déposer le dossier", disabled: false) 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 within "#champ-1" do
find("label", text: "Non").click find("label", text: "Non").click

View file

@ -160,6 +160,7 @@ describe 'shared/dossiers/edit', type: :view do
before do before do
allow(dossier).to receive(:can_passer_en_construction?).and_return(false) allow(dossier).to receive(:can_passer_en_construction?).and_return(false)
allow(dossier.revision).to receive(:ineligibilite_enabled?).and_return(true)
end end
it 'renders broken transitions rules dialog' do it 'renders broken transitions rules dialog' do