2019-10-15-01 (#4409)

2019-10-15-01
This commit is contained in:
Pierre de La Morinerie 2019-10-15 15:38:58 +02:00 committed by GitHub
commit 0a423f3e80
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
15 changed files with 274 additions and 101 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

@ -33,6 +33,8 @@
} }
.ask-avis { .ask-avis {
margin-bottom: 2 * $default-padding;
.avis-notice { .avis-notice {
font-size: 14px; font-size: 14px;
color: $grey; color: $grey;

View file

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

View file

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

View file

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

View file

@ -1,15 +1,23 @@
- if dossier.en_construction? || dossier.en_instruction? || dossier.accepte?
%span.dropdown %span.dropdown
%button.button.primary.dropdown-button -# Dropdown button title
%button.button.primary.dropdown-button{ class: button_or_label_class(dossier) }
= dossier_display_state dossier = dossier_display_state dossier
-# Dropdown content
.dropdown-content.fade-in-down .dropdown-content.fade-in-down
%ul.dropdown-items
- if dossier.en_construction? - if dossier.en_construction?
-# ------------------------------------------------------
-# EN CONSTRUCTION
-# ------------------------------------------------------
%ul.dropdown-items
%li.selected %li.selected
%span.icon.edit %span.icon.edit
.dropdown-description .dropdown-description
%h4 En construction %h4 En construction
Vous permettez à l'usager de modifier ses réponses au formulaire Vous permettez à l'usager de modifier ses réponses au formulaire
%li %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 = 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 %span.icon.in-progress
@ -17,72 +25,83 @@
%h4 Passer en instruction %h4 Passer en instruction
L'usager ne pourra plus modifier le formulaire L'usager ne pourra plus modifier le formulaire
- if dossier.accepte? - elsif dossier.en_instruction?
%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 -# EN INSTRUCTION
%span.icon.in-progress -# ------------------------------------------------------
.dropdown-description %ul.dropdown-items
%h4 Passer en instruction
L'usager ne pourra plus modifier le formulaire
- if dossier.en_instruction?
%li %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 = 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 %span.icon.edit
.dropdown-description .dropdown-description
%h4 Repasser en construction %h4 Repasser en construction
Vous permettrez à l'usager de modifier ses réponses au formulaire Vous permettrez à l'usager de modifier ses réponses au formulaire
%li.selected %li.selected
%span.icon.in-progress %span.icon.in-progress
.dropdown-description .dropdown-description
%h4 En instruction %h4 En instruction
L'usager ne peut modifier son dossier pendant l'instruction L'usager ne peut modifier son dossier pendant l'instruction
%li %li
%a{ href: '#', onclick: "DS.showMotivation(event, 'accept');" } %a{ href: '#', onclick: "DS.showMotivation(event, 'accept');" }
%span.icon.accept %span.icon.accept
.dropdown-description .dropdown-description
%h4 Accepter %h4 Accepter
L'usager sera notifié que son dossier a été accepté L'usager sera notifié que son dossier a été accepté
%li %li
%a{ href: '#', onclick: "DS.showMotivation(event, 'without-continuation');" } %a{ href: '#', onclick: "DS.showMotivation(event, 'without-continuation');" }
%span.icon.without-continuation %span.icon.without-continuation
.dropdown-description .dropdown-description
%h4 Classer sans suite %h4 Classer sans suite
L'usager sera notifié que son dossier a été classé sans suite L'usager sera notifié que son dossier a été classé sans suite
%li %li
%a{ href: '#', onclick: "DS.showMotivation(event, 'refuse');" } %a{ href: '#', onclick: "DS.showMotivation(event, 'refuse');" }
%span.icon.refuse %span.icon.refuse
.dropdown-description .dropdown-description
%h4 Refuser %h4 Refuser
L'usager sera notifié que son dossier a été refusé 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: '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: '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 ?' } = 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 ?' }
- else - elsif dossier.termine?
- if dossier.motivation.present? || dossier.attestation.present? -# ---------------------------------------------------
%span.dropdown -# TERMINÉ
%button.button.dropdown-button{ class: button_or_label_class(dossier) } -# ---------------------------------------------------
= dossier_display_state(dossier, lower: true) %ul.dropdown-items
.dropdown-content.fade-in-down.terminated
- if dossier.motivation.present? - if dossier.motivation.present?
%h4.title Motivation %li.inactive
%p.dossier-motivation= dossier.motivation %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 } = render partial: 'users/dossiers/show/download_justificatif', locals: { dossier: dossier }
- if dossier.attestation.present? - if dossier.attestation.present?
%h4.title Attestation %li
%p.attestation L'acceptation du dossier a envoyé automatiquement une attestation au demandeur = link_to attestation_instructeur_dossier_path(dossier.procedure, dossier), target: '_blank', rel: 'noopener' do
= link_to "Voir l'attestation", attestation_instructeur_dossier_path(dossier.procedure, dossier), target: '_blank', rel: 'noopener', class: 'button' %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 %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 = 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 %span.icon.in-progress
.dropdown-description .dropdown-description
%h4 Repasser en instruction %h4 Repasser en instruction
Lusager sera notifié que son dossier est réexaminé. Lusager sera notifié que son dossier est réexaminé.
- else
%span.label{ class: button_or_label_class(dossier) }
= dossier_display_state(dossier, lower: true)

View file

@ -6,8 +6,11 @@
= form_tag(terminer_instructeur_dossier_path(dossier.procedure, dossier), remote: true, method: :post, class: 'form') do = form_tag(terminer_instructeur_dossier_path(dossier.procedure, dossier), remote: true, method: :post, class: 'form') do
- if title == 'Accepter' - if title == 'Accepter'
= text_area :dossier, :motivation, class: 'motivation-text-area', placeholder: placeholder, required: false = text_area :dossier, :motivation, class: 'motivation-text-area', placeholder: placeholder, required: false
- if dossier.procedure.attestation_template&.activated?
%p.help %p.help
L'acceptation du dossier envoie automatiquement une attestation à l'usager. L'acceptation du dossier envoie automatiquement
= link_to 'une attestation', apercu_attestation_instructeur_dossier_path(dossier.procedure, dossier), target: '_blank', rel: 'noopener', title: "Voir l'attestation qui sera envoyée à l'usager"
à l'usager.
- unspecified_attestation_champs = dossier.unspecified_attestation_champs - unspecified_attestation_champs = dossier.unspecified_attestation_champs
- if unspecified_attestation_champs.present? - if unspecified_attestation_champs.present?
@ -33,7 +36,5 @@
.hidden{ id: "justificatif_motivation_import_#{popup_class}" } .hidden{ id: "justificatif_motivation_import_#{popup_class}" }
= file_field :dossier, :justificatif_motivation, direct_upload: true = file_field :dossier, :justificatif_motivation, direct_upload: true
.text-right .text-right
- if title == 'Accepter' && dossier.procedure.attestation_template&.activated?
= link_to "Voir l'attestation", apercu_attestation_instructeur_dossier_path(dossier.procedure, dossier), target: '_blank', rel: 'noopener', class: 'button', title: "Voir l'attestation qui sera envoyée au demandeur"
%span.button{ onclick: 'DS.motivationCancel();' } Annuler %span.button{ onclick: 'DS.motivationCancel();' } Annuler
= button_tag 'Valider la décision', name: :process_action, value: process_action, class: 'button primary', title: title, data: { confirm: confirm } = button_tag 'Valider la décision', name: :process_action, value: process_action, class: 'button primary', title: title, data: { confirm: confirm }

View file

@ -1,23 +1,23 @@
%section.ask-avis %section.ask-avis
%h1.tab-title Inviter des personnes à donner leur avis %h1.tab-title Inviter des personnes à donner leur avis
%p.avis-notice Les invités pourront consulter, donner un avis sur le dossier et contribuer au fil de messagerie, mais ils ne pourront pas le modifier. %p.avis-notice Les invités pourront consulter le dossier, donner un avis et contribuer au fil de messagerie. Ils ne pourront pas modifier le dossier.
= form_for avis, url: url, html: { class: 'form' } do |f| = form_for avis, url: url, html: { class: 'form' } do |f|
= f.email_field :emails, placeholder: 'Adresses email, séparées par des virgules', required: true, multiple: true, onchange: "javascript:DS.replaceSemicolonByComma(event);" = f.email_field :emails, placeholder: 'Adresses email, séparées par des virgules', required: true, multiple: true, onchange: "javascript:DS.replaceSemicolonByComma(event);"
= f.text_area :introduction, rows: 3, value: avis.introduction || 'Bonjour, merci de me donner votre avis sur ce dossier.', required: true = f.text_area :introduction, rows: 3, value: avis.introduction || 'Bonjour, merci de me donner votre avis sur ce dossier.', required: true
.flex.justify-between.align-baseline .flex.justify-between.align-baseline
- if must_be_confidentiel - if must_be_confidentiel
%p.confidentiel.flex %p.confidentiel.flex
%span.icon.lock %span.icon.lock
%span %span
Cet avis est confidentiel et n'est pas affiché aux autres experts consultés mais est visible par tous les instructeurs Cet avis sera confidentiel : il ne sera pas affiché aux autres experts consultés, mais sera visible par les instructeurs.
.send-wrapper
= f.submit 'Demander un avis', class: 'button send'
- else - else
.confidentiel-wrapper .confidentiel-wrapper
= f.label :confidentiel, 'Cet avis est' = f.label :confidentiel, 'Cet avis sera '
= f.select :confidentiel, [['partagé avec les autres experts', false], ['confidentiel', true]], {}, onchange: "javascript:DS.toggleCondidentielExplanation(event);" = f.select :confidentiel, [['partagé avec les autres experts', false], ['confidentiel', true]], {}, onchange: "javascript:DS.toggleCondidentielExplanation(event);"
.confidentiel-explanation.hidden .confidentiel-explanation.hidden
Il ne sera pas affiché aux autres experts consultés mais sera visible par les instructeurs Il ne sera pas affiché aux autres experts consultés, mais sera visible par les instructeurs.
.send-wrapper
= f.submit 'Demander un avis', class: 'button send' = f.submit 'Demander un avis', class: 'button primary send'

View file

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

View file

@ -62,7 +62,7 @@
- if dossier.attestation.present? - if dossier.attestation.present?
.action .action
= link_to attestation_dossier_path(dossier), target: '_blank', rel: 'noopener', class: 'button primary' do = 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 Télécharger lattestation

View file

@ -145,6 +145,15 @@ FactoryBot.define do
end end
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 trait :with_all_champs do
after(:create) do |dossier, _evaluator| after(:create) do |dossier, _evaluator|
dossier.champs = dossier.procedure.types_de_champ.map do |type_de_champ| 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

View file

@ -16,10 +16,10 @@ describe 'instructeurs/dossiers/state_button_motivation.html.haml', type: :view
context 'with an attestation preview' do context 'with an attestation preview' do
let(:dossier) { create :dossier, :accepte, :with_attestation } let(:dossier) { create :dossier, :accepte, :with_attestation }
it { expect(rendered).to have_text("Voir l'attestation") } it { expect(rendered).to have_link(href: apercu_attestation_instructeur_dossier_path(dossier.procedure, dossier)) }
end end
context 'without an attestation preview' do context 'without an attestation preview' do
it { expect(rendered).not_to have_text("Voir l'attestation") } it { expect(rendered).not_to have_link(href: apercu_attestation_instructeur_dossier_path(dossier.procedure, dossier)) }
end end
end end