From a4932a749c7bae86488cf66c7bba5f92a94ee8be Mon Sep 17 00:00:00 2001 From: Lisa Durand Date: Mon, 27 Feb 2023 17:05:39 +0100 Subject: [PATCH 1/4] improve UX of instruction dropdown menu --- app/assets/stylesheets/buttons.scss | 5 +++++ app/components/dropdown/menu_component.rb | 5 ++++- app/javascript/new_design/instruction-button.js | 7 ++++++- .../dossiers/_instruction_button.html.haml | 17 ++++++++--------- .../_instruction_button_motivation.html.haml | 4 ---- 5 files changed, 23 insertions(+), 15 deletions(-) diff --git a/app/assets/stylesheets/buttons.scss b/app/assets/stylesheets/buttons.scss index 2066e1228..e4333bacd 100644 --- a/app/assets/stylesheets/buttons.scss +++ b/app/assets/stylesheets/buttons.scss @@ -246,6 +246,11 @@ ul.dropdown-items { } } + &.form-inside { + background-color: $white; + margin-top: -2px; + } + &.danger { &:hover { background-color: $medium-red; diff --git a/app/components/dropdown/menu_component.rb b/app/components/dropdown/menu_component.rb index 72457abc1..eb9f38897 100644 --- a/app/components/dropdown/menu_component.rb +++ b/app/components/dropdown/menu_component.rb @@ -9,11 +9,13 @@ class Dropdown::MenuComponent < ApplicationComponent def initialize(wrapper:, wrapper_options: {}, button_options: {}, - menu_options: {}) + menu_options: {}, + role: nil) @wrapper = wrapper @wrapper_options = wrapper_options @button_options = button_options @menu_options = menu_options + @role = role end def wrapper_options @@ -37,6 +39,7 @@ class Dropdown::MenuComponent < ApplicationComponent end def menu_role + return @role if @role forms? ? :region : :menu end diff --git a/app/javascript/new_design/instruction-button.js b/app/javascript/new_design/instruction-button.js index 01ac323cc..dc5645042 100644 --- a/app/javascript/new_design/instruction-button.js +++ b/app/javascript/new_design/instruction-button.js @@ -3,12 +3,17 @@ import { show, hide } from '@utils'; export function showMotivation(event, state) { event.preventDefault(); motivationCancel(); - show(document.querySelector(`.motivation.${state}`)); + const stateElement = document.querySelector(`.motivation.${state}`) + + show(stateElement.parentElement); + show(stateElement); hide(document.querySelector('.dropdown-items')); } export function motivationCancel() { document.querySelectorAll('.motivation').forEach(hide); + document.querySelectorAll('.motivation').forEach(el => hide(el.parentElement)); + show(document.querySelector('.dropdown-items')); } diff --git a/app/views/instructeurs/dossiers/_instruction_button.html.haml b/app/views/instructeurs/dossiers/_instruction_button.html.haml index 82e545fe3..6cf4de10e 100644 --- a/app/views/instructeurs/dossiers/_instruction_button.html.haml +++ b/app/views/instructeurs/dossiers/_instruction_button.html.haml @@ -1,5 +1,5 @@ - if dossier.en_instruction? - = render Dropdown::MenuComponent.new(wrapper: :div, wrapper_options: { data: {'turbo-force': true} }, button_options: { class: [button_or_label_class(dossier)] }) do |menu| + = render Dropdown::MenuComponent.new(wrapper: :div, wrapper_options: { data: {'turbo-force': true} }, button_options: { class: [button_or_label_class(dossier)]}, role: @dossier.en_instruction? ? :region : :menu) do |menu| - menu.with_button_inner_html do Instruire le dossier @@ -10,6 +10,9 @@ %h4 Accepter L’usager sera notifié que son dossier a été accepté + - menu.with_item(class: "hidden inactive form-inside") do + = render partial: 'instructeurs/dossiers/instruction_button_motivation', locals: { dossier: dossier, placeholder: 'Expliquez au demandeur pourquoi ce dossier est accepté (facultatif)', popup_class: 'accept', process_action: 'accepter', title: 'Accepter', confirm: "Confirmez-vous l'acceptation ce dossier ?" } + - menu.with_item do = link_to('#', onclick: "DS.showMotivation(event, 'without-continuation');", role: 'menuitem') do @@ -18,6 +21,8 @@ %h4 Classer sans suite L’usager sera notifié que son dossier a été classé sans suite + - menu.with_item(class: "hidden inactive form-inside") do + = render partial: 'instructeurs/dossiers/instruction_button_motivation', locals: { dossier: dossier, placeholder: 'Expliquez au demandeur pourquoi ce dossier est classé sans suite (obligatoire)', popup_class: 'without-continuation', process_action: 'classer_sans_suite', title: 'Classer sans suite', confirm: 'Confirmez-vous le classement sans suite de ce dossier ?' } - menu.with_item do = link_to('#', onclick: "DS.showMotivation(event, 'refuse');", role: 'menuitem') do @@ -26,11 +31,5 @@ %h4 Refuser L’usager sera notifié que son dossier a été refusé - - menu.with_form do - = render partial: 'instructeurs/dossiers/instruction_button_motivation', locals: { dossier: dossier, popup_title: 'Accepter le dossier', placeholder: 'Expliquez au demandeur pourquoi ce dossier est accepté (facultatif)', popup_class: 'accept', process_action: 'accepter', title: 'Accepter', confirm: "Confirmez-vous l'acceptation ce dossier ?" } - - - menu.with_form do - = render partial: 'instructeurs/dossiers/instruction_button_motivation', locals: { dossier: dossier, popup_title: 'Classer le dossier sans suite', placeholder: 'Expliquez au demandeur pourquoi ce dossier est classé sans suite (obligatoire)', popup_class: 'without-continuation', process_action: 'classer_sans_suite', title: 'Classer sans suite', confirm: 'Confirmez-vous le classement sans suite de ce dossier ?' } - - - menu.with_form do - = render partial: 'instructeurs/dossiers/instruction_button_motivation', locals: { dossier: dossier, popup_title: 'Refuser le dossier', placeholder: 'Expliquez au demandeur pourquoi ce dossier est refusé (obligatoire)', popup_class: 'refuse', process_action: 'refuser', title: 'Refuser', confirm: 'Confirmez-vous le refus de ce dossier ?' } + - menu.with_item(class: "hidden inactive form-inside") do + = render partial: 'instructeurs/dossiers/instruction_button_motivation', locals: { dossier: dossier, placeholder: 'Expliquez au demandeur pourquoi ce dossier est refusé (obligatoire)', popup_class: 'refuse', process_action: 'refuser', title: 'Refuser', confirm: 'Confirmez-vous le refus de ce dossier ?' } diff --git a/app/views/instructeurs/dossiers/_instruction_button_motivation.html.haml b/app/views/instructeurs/dossiers/_instruction_button_motivation.html.haml index 1eff1a76f..397c92710 100644 --- a/app/views/instructeurs/dossiers/_instruction_button_motivation.html.haml +++ b/app/views/instructeurs/dossiers/_instruction_button_motivation.html.haml @@ -1,8 +1,4 @@ .motivation.hidden{ class: popup_class } - %h3.fr-h5 - %span.icon{ class: popup_class } - #{popup_title} - = form_tag(terminer_instructeur_dossier_path(dossier.procedure, dossier), data: { turbo: true, turbo_confirm: confirm }, method: :post, multipart: true, class: 'form') do - if title == 'Accepter' = text_area :dossier, :motivation, class: 'motivation-text-area', placeholder: placeholder, required: false From 7130ea7e998763deb654275dffa84bcdc74bdd27 Mon Sep 17 00:00:00 2001 From: Lisa Durand Date: Tue, 28 Feb 2023 10:49:50 +0100 Subject: [PATCH 2/4] fix specs --- app/javascript/new_design/instruction-button.js | 6 ++++-- .../instructeurs/dossiers/_instruction_button.html.haml | 2 +- .../dossiers/_instruction_button.html.haml_spec.rb | 2 +- 3 files changed, 6 insertions(+), 4 deletions(-) diff --git a/app/javascript/new_design/instruction-button.js b/app/javascript/new_design/instruction-button.js index dc5645042..f2af6c57e 100644 --- a/app/javascript/new_design/instruction-button.js +++ b/app/javascript/new_design/instruction-button.js @@ -3,7 +3,7 @@ import { show, hide } from '@utils'; export function showMotivation(event, state) { event.preventDefault(); motivationCancel(); - const stateElement = document.querySelector(`.motivation.${state}`) + const stateElement = document.querySelector(`.motivation.${state}`); show(stateElement.parentElement); show(stateElement); @@ -12,7 +12,9 @@ export function showMotivation(event, state) { export function motivationCancel() { document.querySelectorAll('.motivation').forEach(hide); - document.querySelectorAll('.motivation').forEach(el => hide(el.parentElement)); + document + .querySelectorAll('.motivation') + .forEach((el) => hide(el.parentElement)); show(document.querySelector('.dropdown-items')); } diff --git a/app/views/instructeurs/dossiers/_instruction_button.html.haml b/app/views/instructeurs/dossiers/_instruction_button.html.haml index 6cf4de10e..ef5adbfb1 100644 --- a/app/views/instructeurs/dossiers/_instruction_button.html.haml +++ b/app/views/instructeurs/dossiers/_instruction_button.html.haml @@ -1,5 +1,5 @@ - if dossier.en_instruction? - = render Dropdown::MenuComponent.new(wrapper: :div, wrapper_options: { data: {'turbo-force': true} }, button_options: { class: [button_or_label_class(dossier)]}, role: @dossier.en_instruction? ? :region : :menu) do |menu| + = render Dropdown::MenuComponent.new(wrapper: :div, wrapper_options: { data: {'turbo-force': true} }, button_options: { class: [button_or_label_class(dossier)]}, role: dossier.en_instruction? ? :region : :menu) do |menu| - menu.with_button_inner_html do Instruire le dossier diff --git a/spec/views/instructeur/dossiers/_instruction_button.html.haml_spec.rb b/spec/views/instructeur/dossiers/_instruction_button.html.haml_spec.rb index 049640877..86e97981c 100644 --- a/spec/views/instructeur/dossiers/_instruction_button.html.haml_spec.rb +++ b/spec/views/instructeur/dossiers/_instruction_button.html.haml_spec.rb @@ -14,7 +14,7 @@ describe 'instructeurs/dossiers/instruction_button.html.haml', type: :view do matcher :have_dropdown_items do |options| match do |rendered| expected_count = options[:count] || 1 - expect(rendered).to have_selector('ul.dropdown-items li', count: expected_count) + expect(rendered).to have_selector('ul.dropdown-items li:not(.hidden)', count: expected_count) end end From 99c5a1f2980630b4dc24eb880da0a33a0af3872b Mon Sep 17 00:00:00 2001 From: Lisa Durand Date: Tue, 28 Feb 2023 16:01:50 +0100 Subject: [PATCH 3/4] use DSFR classes for btn and form inside the dropdown --- ...ch_operation_inline_buttons_component.html.haml | 2 +- .../_instruction_button_motivation.html.haml | 14 +++++++------- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/app/components/dossiers/batch_operation_inline_buttons_component/batch_operation_inline_buttons_component.html.haml b/app/components/dossiers/batch_operation_inline_buttons_component/batch_operation_inline_buttons_component.html.haml index 1f4be9f4a..be2e84e15 100644 --- a/app/components/dossiers/batch_operation_inline_buttons_component/batch_operation_inline_buttons_component.html.haml +++ b/app/components/dossiers/batch_operation_inline_buttons_component/batch_operation_inline_buttons_component.html.haml @@ -15,7 +15,7 @@ %h4= opt[:label] .motivation.accept - = form.text_area :motivation, class: 'motivation-text-area' + = form.text_area :motivation, class: 'fr-input' #justificatif_motivation_suggest_accept.optional-justificatif %button.button{ type: 'button', onclick: "DS.showImportJustificatif('accept');" } Ajouter un justificatif (optionnel) #justificatif_motivation_import_accept.hidden diff --git a/app/views/instructeurs/dossiers/_instruction_button_motivation.html.haml b/app/views/instructeurs/dossiers/_instruction_button_motivation.html.haml index 397c92710..d241281a5 100644 --- a/app/views/instructeurs/dossiers/_instruction_button_motivation.html.haml +++ b/app/views/instructeurs/dossiers/_instruction_button_motivation.html.haml @@ -1,7 +1,7 @@ .motivation.hidden{ class: popup_class } - = form_tag(terminer_instructeur_dossier_path(dossier.procedure, dossier), data: { turbo: true, turbo_confirm: confirm }, method: :post, multipart: true, class: 'form') do + = form_tag(terminer_instructeur_dossier_path(dossier.procedure, dossier), data: { turbo: true, turbo_confirm: confirm }, method: :post, multipart: true) do - if title == 'Accepter' - = text_area :dossier, :motivation, class: 'motivation-text-area', placeholder: placeholder, required: false + = text_area :dossier, :motivation, class: 'fr-input', placeholder: placeholder, required: false - if dossier.attestation_template&.activated? %p.help L’acceptation du dossier envoie automatiquement @@ -26,11 +26,11 @@ - unspecified_annotations_privees.each do |unspecified_annotations_privee| %li= unspecified_annotations_privee.libelle - else - = text_area :dossier, :motivation, class: 'motivation-text-area', placeholder: placeholder, required: true + = text_area :dossier, :motivation, class: 'fr-input', placeholder: placeholder, required: true .optional-justificatif{ id: "justificatif_motivation_suggest_#{popup_class}", onclick: "DS.showImportJustificatif('#{popup_class}');" } - .button Ajouter un justificatif (optionnel) + .fr-btn.fr-btn--tertiary-no-outline.fr-btn--icon-left.fr-icon-attachment-line.fr-ml-0 Ajouter un justificatif (optionnel) .hidden{ id: "justificatif_motivation_import_#{popup_class}" } = file_field :dossier, :justificatif_motivation, direct_upload: true - .text-right - %span.button{ onclick: 'DS.motivationCancel();' } Annuler - = button_tag 'Valider la décision', name: :process_action, value: process_action, class: 'button primary', title: title + .text-right.fr-mt-2w + %span.fr-btn.fr-btn--secondary{ onclick: 'DS.motivationCancel();' } Annuler + = button_tag 'Valider la décision', name: :process_action, value: process_action, class: 'fr-btn fr-mr-0', title: title From 3aac56042ecee3f21e17c1581b2111ec785f6d2a Mon Sep 17 00:00:00 2001 From: Lisa Durand Date: Tue, 28 Feb 2023 16:42:24 +0100 Subject: [PATCH 4/4] fix tests --- spec/views/instructeur/dossiers/show.html.haml_spec.rb | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/spec/views/instructeur/dossiers/show.html.haml_spec.rb b/spec/views/instructeur/dossiers/show.html.haml_spec.rb index f45a062a3..af0c65b74 100644 --- a/spec/views/instructeur/dossiers/show.html.haml_spec.rb +++ b/spec/views/instructeur/dossiers/show.html.haml_spec.rb @@ -73,7 +73,8 @@ describe 'instructeurs/dossiers/show.html.haml', type: :view do expect(subject).to have_link('Repasser en construction', href: repasser_en_construction_instructeur_dossier_path(dossier.procedure, dossier)) expect(subject).to have_link('Ne plus suivre', href: unfollow_instructeur_dossier_path(dossier.procedure, dossier)) expect(subject).to have_button('Instruire le dossier') - expect(subject).to have_selector('.header-actions ul:first-child .fr-btn', count: 3) + expect(subject).to have_selector('.header-actions ul:first-child > li a.fr-btn', count: 2) + expect(subject).to have_selector('.header-actions ul:first-child > li.instruction-button', count: 1) end end