diff --git a/app/views/instructeurs/dossiers/_expiration_banner.html.haml b/app/views/instructeurs/dossiers/_expiration_banner.html.haml index 33d796b8d..3c18a69bf 100644 --- a/app/views/instructeurs/dossiers/_expiration_banner.html.haml +++ b/app/views/instructeurs/dossiers/_expiration_banner.html.haml @@ -1,6 +1,6 @@ -# small expires mention - if dossier.expirable? - %p.expires_at.mb-2 + %p.expires_at.fr-mb-1w %small = t("shared.dossiers.header.expires_at.#{dossier.state}", date: safe_expiration_date(dossier), duree_conservation_totale: dossier.duree_totale_conservation_in_months) @@ -25,4 +25,3 @@ - elsif dossier.en_instruction? && dossier.procedure.procedure_expires_when_termine_enabled %p.expires_at_en_instruction %small= t("shared.dossiers.header.expires_at.en_instruction") - diff --git a/app/views/instructeurs/dossiers/_header.html.haml b/app/views/instructeurs/dossiers/_header.html.haml index 59e015a16..aeb8eb750 100644 --- a/app/views/instructeurs/dossiers/_header.html.haml +++ b/app/views/instructeurs/dossiers/_header.html.haml @@ -23,6 +23,29 @@ = render(partial: 'instructeurs/dossiers/expiration_banner', locals: {dossier: dossier}) + - if dossier.motivation.present? + %p.fr-mb-1w + %small + %strong + Motivation : + « #{dossier.motivation} » + + - if dossier.justificatif_motivation.attached? + %p.fr-mb-0 + %small + %strong + Justificatif : + Ce justificatif joint par l’instructeur a été envoyé au demandeur. + = render partial: 'users/dossiers/show/download_justificatif', locals: { dossier: dossier } + + - if dossier.attestation.present? + %p.fr-mb-0 + %small + %strong + Cette attestation a été envoyée automatiquement au demandeur. + = link_to('Voir l’attestation', attestation_instructeur_dossier_path(dossier.procedure, dossier), target: '_blank', rel: 'noopener') + + %nav.tabs %ul - notifications_summary = current_instructeur.notifications_for_dossier(dossier) diff --git a/app/views/instructeurs/procedures/_dossier_actions.html.haml b/app/views/instructeurs/procedures/_dossier_actions.html.haml index 8c4b5ec9d..b1b71012e 100644 --- a/app/views/instructeurs/procedures/_dossier_actions.html.haml +++ b/app/views/instructeurs/procedures/_dossier_actions.html.haml @@ -19,7 +19,7 @@ = link_to( archive_instructeur_dossier_path(procedure_id, dossier_id), method: :patch, class: 'fr-btn fr-icon-folder-2-line') do Archiver le dossier - = link_to('', instructeur_dossier_path(procedure_id, dossier_id), method: :delete, class: 'fr-btn fr-btn--secondary fr-icon-delete-line icon-only') + = link_to('', instructeur_dossier_path(procedure_id, dossier_id), method: :delete, class: 'fr-btn fr-btn--secondary fr-icon-delete-line icon-only', title: t('views.instructeurs.dossiers.delete_dossier')) - elsif Dossier::EN_CONSTRUCTION_OU_INSTRUCTION.include?(state) diff --git a/app/views/shared/dossiers/_infos_generales.html.haml b/app/views/shared/dossiers/_infos_generales.html.haml index 369667d56..5896b9427 100644 --- a/app/views/shared/dossiers/_infos_generales.html.haml +++ b/app/views/shared/dossiers/_infos_generales.html.haml @@ -4,23 +4,9 @@ %td.libelle Déposé le : %td= l(dossier.depose_at, format: '%d %B %Y') - - if dossier.motivation.present? - %tr - %td.libelle Motivation : - %td - .action - = dossier.motivation - - if dossier.justificatif_motivation.attached? %tr %td.libelle Justificatif : %td .action = render Attachment::ShowComponent.new(attachment: dossier.justificatif_motivation.attachment) - - - if dossier.attestation.present? - %tr - %td.libelle Attestation : - %td - .action - = link_to(attestation_instructeur_dossier_path(dossier.procedure, dossier), target: '_blank', rel: 'noopener') diff --git a/app/views/users/dossiers/_expiration_banner.html.haml b/app/views/users/dossiers/_expiration_banner.html.haml index 6320a8c73..8f9e9f529 100644 --- a/app/views/users/dossiers/_expiration_banner.html.haml +++ b/app/views/users/dossiers/_expiration_banner.html.haml @@ -1,6 +1,6 @@ -# small expires mention - if dossier.expirable? - %p.expires_at.mb-2 + %p.expires_at.fr-mb-1w %small= t("shared.dossiers.header.expires_at.#{dossier.state}", date: safe_expiration_date(dossier), duree_conservation_totale: dossier.duree_totale_conservation_in_months) - if dossier.close_to_expiration? @@ -21,4 +21,3 @@ - elsif dossier.en_instruction? && dossier.procedure.procedure_expires_when_termine_enabled %p.expires_at_en_instruction %small= t("shared.dossiers.header.expires_at.en_instruction") - diff --git a/spec/controllers/instructeurs/dossiers_controller_spec.rb b/spec/controllers/instructeurs/dossiers_controller_spec.rb index ab5873235..9f85aff93 100644 --- a/spec/controllers/instructeurs/dossiers_controller_spec.rb +++ b/spec/controllers/instructeurs/dossiers_controller_spec.rb @@ -153,16 +153,16 @@ describe Instructeurs::DossiersController, type: :controller do it { expect(dossier.reload.state).to eq(Dossier.states.fetch(:en_instruction)) } it { expect(instructeur.follow?(dossier)).to be true } - it { expect(response).to have_http_status(:ok) } - it { expect(response.body).to include('.header-actions') } + it { expect(response).to redirect_to(instructeur_procedure_path(dossier.procedure)) } + it { expect(flash.notice).to eq("Dossier passé en instruction.") } context 'when the dossier has already been put en_instruction' do let(:dossier) { create(:dossier, :en_instruction, procedure: procedure) } it 'warns about the error' do expect(dossier.reload.state).to eq(Dossier.states.fetch(:en_instruction)) - expect(response).to have_http_status(:ok) - expect(response.body).to include('Le dossier est déjà en instruction.') + expect(response).to redirect_to(instructeur_procedure_path(dossier.procedure)) + expect(flash.alert).to eq("Le dossier est déjà en instruction.") end end @@ -174,8 +174,8 @@ describe Instructeurs::DossiersController, type: :controller do end it 'warns about the error' do - expect(response).to have_http_status(:ok) - expect(response.body).to include('Le dossier est en ce moment accepté : il n’est pas possible de le passer en instruction.') + expect(response).to redirect_to(instructeur_procedure_path(dossier.procedure)) + expect(flash.alert).to eq("Le dossier est en ce moment accepté : il n’est pas possible de le passer en instruction.") end end @@ -199,16 +199,16 @@ describe Instructeurs::DossiersController, type: :controller do end it { expect(dossier.reload.state).to eq(Dossier.states.fetch(:en_construction)) } - it { expect(response).to have_http_status(:ok) } - it { expect(response.body).to include('.header-actions') } + it { expect(response).to redirect_to(instructeur_procedure_path(dossier.procedure)) } + it { expect(flash.notice).to eq("Dossier repassé en construction.") } context 'when the dossier has already been put en_construction' do let(:dossier) { create(:dossier, :en_construction, procedure: procedure) } it 'warns about the error' do expect(dossier.reload.state).to eq(Dossier.states.fetch(:en_construction)) - expect(response).to have_http_status(:ok) - expect(response.body).to include('Le dossier est déjà en construction.') + expect(response).to redirect_to(instructeur_procedure_path(dossier.procedure)) + expect(flash.alert).to eq("Le dossier est déjà en construction.") end end @@ -235,8 +235,8 @@ describe Instructeurs::DossiersController, type: :controller do context 'when the dossier is refuse' do it { expect(dossier.reload.state).to eq(Dossier.states.fetch(:en_instruction)) } - it { expect(response).to have_http_status(:ok) } - it { expect(response.body).to include('.header-actions') } + it { expect(response).to redirect_to(instructeur_procedure_path(dossier.procedure)) } + it { expect(flash.notice).to eq("Le dossier #{dossier.id} a été repassé en instruction.") } end context 'when the dossier has already been put en_instruction' do @@ -244,8 +244,8 @@ describe Instructeurs::DossiersController, type: :controller do it 'warns about the error' do expect(dossier.reload.state).to eq(Dossier.states.fetch(:en_instruction)) - expect(response).to have_http_status(:ok) - expect(response.body).to include('Le dossier est déjà en instruction.') + expect(response).to redirect_to(instructeur_procedure_path(dossier.procedure)) + expect(flash.alert).to eq("Le dossier est déjà en instruction.") end end @@ -254,7 +254,8 @@ describe Instructeurs::DossiersController, type: :controller do it 'it is possible to go back to en_instruction as instructeur' do expect(dossier.reload.state).to eq(Dossier.states.fetch(:en_instruction)) - expect(response).to have_http_status(:ok) + expect(response).to redirect_to(instructeur_procedure_path(dossier.procedure)) + expect(flash.notice).to eq("Le dossier #{dossier.id} a été repassé en instruction.") end end diff --git a/spec/system/instructeurs/instruction_spec.rb b/spec/system/instructeurs/instruction_spec.rb index 7cea056ca..b0222bbbc 100644 --- a/spec/system/instructeurs/instruction_spec.rb +++ b/spec/system/instructeurs/instruction_spec.rb @@ -37,16 +37,14 @@ describe 'Instructing a dossier:', js: true do click_on dossier.user.email expect(page).to have_current_path(instructeur_dossier_path(procedure, dossier)) - click_on 'En construction' - accept_confirm do - click_on 'Passer en instruction' - end - expect(page).to have_text('En instruction') + click_on 'Passer en instruction' + + expect(page).to have_text('en instruction') dossier.reload expect(dossier.state).to eq(Dossier.states.fetch(:en_instruction)) - click_on 'En instruction' + click_on 'Instruire le dossier' within('.state-button') do click_on 'Accepter' @@ -69,10 +67,10 @@ describe 'Instructing a dossier:', js: true do click_on procedure.libelle click_on 'traité' - click_on 'Actions' # destroy from list - click_on 'Supprimer le dossier' + expect(page).to have_link('Repasser en instruction') + page.click_link('', title: 'Supprimer le dossier') click_on 'traité' - expect(page).not_to have_button('Actions') + expect(page).not_to have_link('Repasser en instruction') end scenario 'An instructeur can destroy a dossier from view' do @@ -81,10 +79,7 @@ describe 'Instructing a dossier:', js: true do dossier.passer_en_instruction(instructeur: instructeur) dossier.accepter!(instructeur: instructeur) visit instructeur_dossier_path(procedure, dossier) - click_on 'Actions' # destroy from view - within '.user-dossier-actions' do - click_on 'Supprimer le dossier' - end + page.click_link('', title: 'Supprimer le dossier') end scenario 'A instructeur can follow/unfollow a dossier' do diff --git a/spec/views/instructeur/dossiers/_state_button.html.haml_spec.rb b/spec/views/instructeur/dossiers/_state_button.html.haml_spec.rb index 5c71fc460..c0aa3157b 100644 --- a/spec/views/instructeur/dossiers/_state_button.html.haml_spec.rb +++ b/spec/views/instructeur/dossiers/_state_button.html.haml_spec.rb @@ -29,92 +29,15 @@ describe 'instructeurs/dossiers/state_button.html.haml', type: :view do 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_title('Instruire le dossier') + expect(rendered).to have_dropdown_items(count: 3) 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: 2) - 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 l’attestation') - 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(virus_scan_result: ActiveStorage::VirusScanner::SAFE) - dossier - end - - it 'allows to download the justificatif' do - expect(rendered).to have_dropdown_item('Justificatif') - expect(response).to have_css("a[href*='/rails/active_storage/blobs/']", text: dossier.justificatif_motivation.attachment.filename.to_s) - 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 diff --git a/spec/views/instructeur/dossiers/show.html.haml_spec.rb b/spec/views/instructeur/dossiers/show.html.haml_spec.rb index 0ae1552dd..726bb7b6f 100644 --- a/spec/views/instructeur/dossiers/show.html.haml_spec.rb +++ b/spec/views/instructeur/dossiers/show.html.haml_spec.rb @@ -8,15 +8,120 @@ describe 'instructeurs/dossiers/show.html.haml', type: :view do assign(:dossier, dossier) end - subject! { render } + subject { render } it 'renders the header' do - expect(rendered).to have_text("Dossier nº #{dossier.id}") + expect(subject).to have_text("Dossier nº #{dossier.id}") end it 'renders the dossier infos' do - expect(rendered).to have_text('Identité') - expect(rendered).to have_text('Demande') + expect(subject).to have_text('Identité') + expect(subject).to have_text('Demande') + end + + it 'renders the correct dossier state' do + expect(subject).to have_text('en construction') + end + + context 'with a motivation' do + let(:dossier) { create :dossier, :accepte, :with_motivation } + + it 'displays the motivation text' do + expect(subject).to have_content(dossier.motivation) + end + end + + context 'with an attestation' do + let(:dossier) { create :dossier, :accepte, :with_attestation } + + it 'provides a link to the attestation' do + expect(subject).to have_text('Cette attestation a été envoyée automatiquement au demandeur.') + expect(subject).to have_link(href: attestation_instructeur_dossier_path(dossier.procedure, dossier)) + end + end + + context 'with a justificatif' do + let(:dossier) do + dossier = create(:dossier, :accepte, :with_justificatif) + dossier.justificatif_motivation.blob.update(virus_scan_result: ActiveStorage::VirusScanner::SAFE) + dossier + end + + it 'allows to download the justificatif' do + expect(subject).to have_css("a[href*='/rails/active_storage/blobs/']", text: dossier.justificatif_motivation.attachment.filename.to_s) + end + end + + context 'en_contruction' do + let(:dossier) { create(:dossier, :en_construction) } + it 'displays the correct actions' do + expect(subject).to have_link('Passer en instruction', href: passer_en_instruction_instructeur_dossier_path(dossier.procedure, dossier)) + expect(subject).to have_link('Suivre le dossier', href: follow_instructeur_dossier_path(dossier.procedure, dossier)) + expect(subject).to have_selector('.header-actions ul:first-child .fr-btn', count: 2) + end + end + + context 'en_instruction' do + let(:dossier) { create(:dossier, :en_instruction) } + + before do + current_instructeur.followed_dossiers << dossier + render + end + + it 'displays the correct actions' 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) + end + end + + context 'accepte' do + let(:dossier) { create(:dossier, :accepte) } + + it 'displays the correct actions' do + expect(subject).to have_link('Repasser en instruction', href: repasser_en_instruction_instructeur_dossier_path(dossier.procedure, dossier)) + expect(subject).to have_link('Archiver le dossier', href: archive_instructeur_dossier_path(dossier.procedure, dossier)) + expect(subject).to have_selector('[title^="Supprimer le dossier"]') + expect(subject).to have_selector('.header-actions ul:first-child .fr-btn', count: 3) + end + end + + context 'supprime' do + let(:dossier) { create(:dossier, :accepte) } + + before do + dossier.hide_and_keep_track!(current_instructeur, :instructeur_request) + render + end + + it 'displays the correct actions' do + expect(subject).to have_link('Restaurer', href: restore_instructeur_dossier_path(dossier.procedure, dossier)) + expect(subject).to have_selector('.header-actions ul:first-child .fr-btn', count: 1) + end + end + + context 'expirant' do + let(:procedure) { create(:procedure, :published, duree_conservation_dossiers_dans_ds: 6, procedure_expires_when_termine_enabled: true) } + let!(:dossier) { create(:dossier, state: :accepte, procedure: procedure, processed_at: 175.days.ago) } + + it 'displays the correct actions' do + expect(subject).to have_text('Conserver un mois de plus') + expect(subject).to have_link('Repasser en instruction', href: repasser_en_instruction_instructeur_dossier_path(dossier.procedure, dossier)) + expect(subject).to have_link('Archiver le dossier', href: archive_instructeur_dossier_path(dossier.procedure, dossier)) + expect(subject).to have_selector('[title^="Supprimer le dossier"]') + expect(subject).to have_selector('.header-actions ul:first-child .fr-btn', count: 4) + end + end + + context 'archived' do + let(:dossier) { create(:dossier, :accepte, :archived) } + + it 'displays the correct actions' do + expect(subject).to have_link('Désarchiver le dossier', href: unarchive_instructeur_dossier_path(dossier.procedure, dossier)) + expect(subject).to have_selector('.header-actions ul:first-child .fr-btn', count: 1) + end end context 'when the user is logged in with france connect' do @@ -39,7 +144,7 @@ describe 'instructeurs/dossiers/show.html.haml', type: :view do let(:dossier) { create(:dossier, :en_construction, :with_entreprise, as_degraded_mode: false) } it 'contains no warning' do - expect(rendered).not_to have_text("Les services de l’INSEE sont indisponibles") + expect(subject).not_to have_text("Les services de l’INSEE sont indisponibles") end end @@ -47,7 +152,7 @@ describe 'instructeurs/dossiers/show.html.haml', type: :view do let(:dossier) { create(:dossier, :en_construction, :with_entreprise, as_degraded_mode: true) } it 'warns the instructeur' do - expect(rendered).to have_text("Les services de l’INSEE sont indisponibles") + expect(subject).to have_text("Les services de l’INSEE sont indisponibles") end end end