[Instructeur] Améliore le dropdown de changement d'état d'un do… (#4401)

Instructeur : amélioration du menu de changement d'état d'un dossier
This commit is contained in:
Pierre de La Morinerie 2019-10-15 13:35:48 +02:00 committed by GitHub
commit dec5cd58e4
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
11 changed files with 256 additions and 86 deletions

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="20"><path d="M11.5 8H15l-7 7-7-7h3.5V1h7zM1 19h14" stroke="#0069cc" stroke-linecap="round" stroke-linejoin="round" stroke-width="2" fill="#fff" fill-opacity=".981" fill-rule="evenodd"/></svg>

After

Width:  |  Height:  |  Size: 250 B

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="24" height="24"><g fill="none" fill-rule="evenodd"><path d="M0 0h24v24H0z"/><path d="M20 7V3a2 2 0 0 0-2-2H6a2 2 0 0 0-2 2v18c0 1.1.901 2 2 2h12c1.099 0 2-.9 2-2V7" stroke-linecap="round" stroke-linejoin="round" stroke="#0069CC" stroke-width="2"/></g><g fill="none" fill-rule="evenodd"><path d="M4.877 2.014h14.607V16.62H4.877z"/><path d="M8.563 12.523l2.977 3.385 3.944-6.903" stroke="#0069cc" stroke-width="1.9998924599999999" stroke-linecap="round" stroke-linejoin="round"/></g></svg>

After

Width:  |  Height:  |  Size: 534 B

View file

@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" width="32" height="32"><g data-name="Layer 78" transform="matrix(1.59996 0 0 1.57052 -3.2 -2.846)" fill="#0069cc"><circle cx="12" cy="12" r="2"/><path d="M21.92 11.62a10.74 10.74 0 0 0-19.84 0 .94.94 0 0 0 0 .76 10.74 10.74 0 0 0 19.84 0 .94.94 0 0 0 0-.76zM12 16a4 4 0 1 1 4-4 4 4 0 0 1-4 4z"/></g></svg>

After

Width:  |  Height:  |  Size: 345 B

View file

@ -206,7 +206,6 @@
border-bottom: 1px solid $border-grey;
font-size: 12px;
min-width: 300px;
cursor: pointer;
&.selected {
cursor: default;
@ -217,8 +216,9 @@
}
&.selected,
&:hover {
&:hover:not(.inactive) {
background: $light-grey;
cursor: pointer;
}
&.danger {
@ -267,8 +267,9 @@
margin-bottom: $default-spacer;
}
&.with-top-border {
border-top: 1px solid $grey;
p + h4,
p + p, {
margin-top: $default-spacer;
}
}

View file

@ -63,7 +63,15 @@
background-image: image-url("icons/attachment.svg");
}
&.preview {
background-image: image-url("icons/preview.svg");
}
&.download {
background-image: image-url("icons/download.svg");
}
&.download-white {
background-image: image-url("icons/download-white.svg");
}
@ -71,6 +79,11 @@
background-image: image-url("icons/lock.svg");
}
&.justificatif {
background-image: image-url("icons/justificatif.svg");
}
&.printer {
background-image: image-url("icons/printer.svg");
}

View file

@ -5,7 +5,7 @@
margin-bottom: 20px;
}
.icon.download {
.icon.download-white {
background-color: $blue;
box-shadow: 0px 0px 1px 2px $blue;
}

View file

@ -1,88 +1,107 @@
- if dossier.en_construction? || dossier.en_instruction? || dossier.accepte?
%span.dropdown
%button.button.primary.dropdown-button
= dossier_display_state dossier
.dropdown-content.fade-in-down
%ul.dropdown-items
- if dossier.en_construction?
%li.selected
%span.icon.edit
.dropdown-description
%h4 En construction
Vous permettez à l'usager de modifier ses réponses au formulaire
%li
= link_to passer_en_instruction_instructeur_dossier_path(dossier.procedure, dossier), method: :post, data: { remote: true, confirm: "Confirmez-vous le passage en instruction de ce dossier ?" } do
%span.icon.in-progress
.dropdown-description
%h4 Passer en instruction
L'usager ne pourra plus modifier le formulaire
%span.dropdown
-# Dropdown button title
%button.button.primary.dropdown-button{ class: button_or_label_class(dossier) }
= dossier_display_state dossier
- if dossier.accepte?
%li
= link_to repasser_en_instruction_instructeur_dossier_path(dossier.procedure, dossier), method: :post, data: { remote: true, confirm: "Confirmez-vous le passage en instruction de ce dossier ?" } do
%span.icon.in-progress
.dropdown-description
%h4 Passer en instruction
L'usager ne pourra plus modifier le formulaire
- if dossier.en_instruction?
%li
= link_to repasser_en_construction_instructeur_dossier_path(dossier.procedure, dossier), method: :post, data: { remote:true, confirm: "Confirmez-vous le passage en construction de ce dossier ?" } do
%span.icon.edit
.dropdown-description
%h4 Repasser en construction
Vous permettrez à l'usager de modifier ses réponses au formulaire
%li.selected
-# Dropdown content
.dropdown-content.fade-in-down
- if dossier.en_construction?
-# ------------------------------------------------------
-# EN CONSTRUCTION
-# ------------------------------------------------------
%ul.dropdown-items
%li.selected
%span.icon.edit
.dropdown-description
%h4 En construction
Vous permettez à l'usager de modifier ses réponses au formulaire
%li
= link_to passer_en_instruction_instructeur_dossier_path(dossier.procedure, dossier), method: :post, data: { remote: true, confirm: "Confirmez-vous le passage en instruction de ce dossier ?" } do
%span.icon.in-progress
.dropdown-description
%h4 En instruction
L'usager ne peut modifier son dossier pendant l'instruction
%li
%a{ href: '#', onclick: "DS.showMotivation(event, 'accept');" }
%span.icon.accept
.dropdown-description
%h4 Accepter
L'usager sera notifié que son dossier a été accepté
%li
%a{ href: '#', onclick: "DS.showMotivation(event, 'without-continuation');" }
%span.icon.without-continuation
.dropdown-description
%h4 Classer sans suite
L'usager sera notifié que son dossier a été classé sans suite
%li
%a{ href: '#', onclick: "DS.showMotivation(event, 'refuse');" }
%span.icon.refuse
.dropdown-description
%h4 Refuser
L'usager sera notifié que son dossier a été refusé
= render partial: 'instructeurs/dossiers/state_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 ?" }
= render partial: 'instructeurs/dossiers/state_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 ?' }
= render partial: 'instructeurs/dossiers/state_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 ?' }
%h4 Passer en instruction
L'usager ne pourra plus modifier le formulaire
- else
- if dossier.motivation.present? || dossier.attestation.present?
%span.dropdown
%button.button.dropdown-button{ class: button_or_label_class(dossier) }
= dossier_display_state(dossier, lower: true)
.dropdown-content.fade-in-down.terminated
- elsif dossier.en_instruction?
-# ------------------------------------------------------
-# EN INSTRUCTION
-# ------------------------------------------------------
%ul.dropdown-items
%li
= link_to repasser_en_construction_instructeur_dossier_path(dossier.procedure, dossier), method: :post, data: { remote:true, confirm: "Confirmez-vous le passage en construction de ce dossier ?" } do
%span.icon.edit
.dropdown-description
%h4 Repasser en construction
Vous permettrez à l'usager de modifier ses réponses au formulaire
%li.selected
%span.icon.in-progress
.dropdown-description
%h4 En instruction
L'usager ne peut modifier son dossier pendant l'instruction
%li
%a{ href: '#', onclick: "DS.showMotivation(event, 'accept');" }
%span.icon.accept
.dropdown-description
%h4 Accepter
L'usager sera notifié que son dossier a été accepté
%li
%a{ href: '#', onclick: "DS.showMotivation(event, 'without-continuation');" }
%span.icon.without-continuation
.dropdown-description
%h4 Classer sans suite
L'usager sera notifié que son dossier a été classé sans suite
%li
%a{ href: '#', onclick: "DS.showMotivation(event, 'refuse');" }
%span.icon.refuse
.dropdown-description
%h4 Refuser
L'usager sera notifié que son dossier a été refusé
= render partial: 'instructeurs/dossiers/state_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 ?" }
= render partial: 'instructeurs/dossiers/state_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 ?' }
= render partial: 'instructeurs/dossiers/state_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 ?' }
- elsif dossier.termine?
-# ---------------------------------------------------
-# TERMINÉ
-# ---------------------------------------------------
%ul.dropdown-items
- if dossier.motivation.present?
%h4.title Motivation
%p.dossier-motivation= dossier.motivation
= render partial: 'users/dossiers/show/download_justificatif', locals: { dossier: dossier }
%li.inactive
%span.icon.info
.dropdown-description
%h4 Motivation
%p « #{dossier.motivation} »
- if dossier.justificatif_motivation.attached?
%li.inactive
%span.icon.justificatif
.dropdown-description
%h4 Justificatif
%p Ce justificatif joint par linstructeur a été envoyé au demandeur.
= render partial: 'users/dossiers/show/download_justificatif', locals: { dossier: dossier }
- if dossier.attestation.present?
%h4.title Attestation
%p.attestation L'acceptation du dossier a envoyé automatiquement une attestation au demandeur
= link_to "Voir l'attestation", attestation_instructeur_dossier_path(dossier.procedure, dossier), target: '_blank', rel: 'noopener', class: 'button'
%li
= link_to attestation_instructeur_dossier_path(dossier.procedure, dossier), target: '_blank', rel: 'noopener' do
%span.icon.preview
.dropdown-description
%h4 Voir lattestation
%p Cette attestation a été envoyée automatiquement au demandeur.
- if dossier.refuse? || dossier.sans_suite?
%ul.dropdown-items.with-top-border
%li
= link_to repasser_en_instruction_instructeur_dossier_path(dossier.procedure, dossier), method: :post, data: { remote:true, confirm: "Voulez vous remettre le dossier #{dossier.id} en instruction ?" } do
%span.icon.in-progress
.dropdown-description
%h4 Repasser en instruction
Lusager sera notifié que son dossier est réexaminé.
- else
%span.label{ class: button_or_label_class(dossier) }
= dossier_display_state(dossier, lower: true)
%li
= link_to repasser_en_instruction_instructeur_dossier_path(dossier.procedure, dossier), method: :post, data: { remote:true, confirm: "Voulez vous remettre le dossier #{dossier.id} en instruction ?" } do
%span.icon.in-progress
.dropdown-description
%h4 Repasser en instruction
Lusager sera notifié que son dossier est réexaminé.

View file

@ -16,6 +16,7 @@
%span.icon.bubble
%span.icon.attachment
%span.icon.lock
%span.icon.justificatif
%span.icon.printer
%span.icon.account
%span.icon.person
@ -29,7 +30,9 @@
%span.icon.help
%span.icon.phone
%span.icon.clock
%span.icon.preview
%span.icon.download
%span.icon.download-white
%span.icon.move-handle
%span.icon.frown
%span.icon.meh

View file

@ -62,7 +62,7 @@
- if dossier.attestation.present?
.action
= link_to attestation_dossier_path(dossier), target: '_blank', rel: 'noopener', class: 'button primary' do
%span.icon.download
%span.icon.download-white
Télécharger lattestation

View file

@ -145,6 +145,15 @@ FactoryBot.define do
end
end
trait :with_justificatif do
after(:create) do |dossier, _evaluator|
dossier.justificatif_motivation.attach(
io: StringIO.new('Hello World'),
filename: 'hello.txt'
)
end
end
trait :with_all_champs do
after(:create) do |dossier, _evaluator|
dossier.champs = dossier.procedure.types_de_champ.map do |type_de_champ|

View file

@ -0,0 +1,122 @@
require 'spec_helper'
describe 'instructeurs/dossiers/state_button.html.haml', type: :view do
include DossierHelper
subject! do
render('instructeurs/dossiers/state_button.html.haml', dossier: dossier)
end
matcher :have_dropdown_title do |expected_title|
match do |rendered|
expect(rendered).to have_selector('.dropdown .dropdown-button', text: expected_title)
end
end
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)
end
end
matcher :have_dropdown_item do |expected_title, options = {}|
match do |rendered|
expected_href = options[:href]
if (expected_href.present?)
expect(rendered).to have_selector("ul.dropdown-items li a[href='#{expected_href}']", text: expected_title)
else
expect(rendered).to have_selector('ul.dropdown-items li', text: expected_title)
end
end
end
context 'brouillon' do
# Currently the state button is not supposed to be displayed for brouillons.
# But better have a sane fallback than crashing.
let(:dossier) { create(:dossier) }
it 'renders a dropdown' do
expect(rendered).to have_dropdown_title('Brouillon')
expect(rendered).to have_dropdown_items(count: 0)
end
end
context 'en_contruction' do
let(:dossier) { create(:dossier, :en_construction) }
it 'renders a dropdown' do
expect(rendered).to have_dropdown_title('En construction')
expect(rendered).to have_dropdown_items(count: 2)
expect(rendered).to have_dropdown_item('En construction')
expect(rendered).to have_dropdown_item('Passer en instruction', href: passer_en_instruction_instructeur_dossier_path(dossier.procedure, dossier))
end
end
context 'en_instruction' do
let(:dossier) { create(:dossier, :en_instruction) }
it 'renders a dropdown' do
expect(rendered).to have_dropdown_title('En instruction')
expect(rendered).to have_dropdown_items(count: 5)
expect(rendered).to have_dropdown_item('Repasser en construction', href: repasser_en_construction_instructeur_dossier_path(dossier.procedure, dossier))
expect(rendered).to have_dropdown_item('En instruction')
expect(rendered).to have_dropdown_item('Accepter')
expect(rendered).to have_dropdown_item('Classer sans suite')
expect(rendered).to have_dropdown_item('Refuser')
end
end
shared_examples 'a dropdown for a closed state' do |state|
let(:dossier) { create :dossier, state }
it 'renders a dropdown' do
expect(rendered).to have_dropdown_title(dossier_display_state(dossier))
expect(rendered).to have_dropdown_items(count: 1)
expect(rendered).to have_dropdown_item('Repasser en instruction', href: repasser_en_instruction_instructeur_dossier_path(dossier.procedure, dossier))
end
context 'with a motivation' do
let(:dossier) { create :dossier, state, :with_motivation }
it 'displays the motivation text' do
expect(rendered).to have_dropdown_item('Motivation')
expect(rendered).to have_content(dossier.motivation)
end
end
context 'with an attestation' do
let(:dossier) { create :dossier, state, :with_attestation }
it 'provides a link to the attestation' do
expect(rendered).to have_dropdown_item('Voir lattestation')
expect(rendered).to have_link(href: attestation_instructeur_dossier_path(dossier.procedure, dossier))
end
end
context 'with a justificatif' do
let(:dossier) do
dossier = create(:dossier, state, :with_justificatif)
dossier.justificatif_motivation.blob.update(metadata: dossier.justificatif_motivation.blob.metadata.merge(virus_scan_result: ActiveStorage::VirusScanner::SAFE))
dossier
end
it 'allows to download the justificatif' do
expect(rendered).to have_dropdown_item('Justificatif')
expect(rendered).to have_link(href: url_for(dossier.justificatif_motivation.attachment.blob))
end
end
end
context 'accepte' do
it_behaves_like 'a dropdown for a closed state', :accepte
end
context 'refuse' do
it_behaves_like 'a dropdown for a closed state', :refuse
end
context 'sans_suite' do
it_behaves_like 'a dropdown for a closed state', :sans_suite
end
end