diff --git a/app/assets/stylesheets/dossiers_table.scss b/app/assets/stylesheets/dossiers_table.scss index 32fec296e..7d836033c 100644 --- a/app/assets/stylesheets/dossiers_table.scss +++ b/app/assets/stylesheets/dossiers_table.scss @@ -83,3 +83,11 @@ width: 200px; } } + +.file-hidden-by-user { + background-color: rgba(242, 137, 0, 0.6); + + &:hover { + background-color: rgba(242, 137, 0, 0.6) !important; + } +} diff --git a/app/controllers/users/dossiers_controller.rb b/app/controllers/users/dossiers_controller.rb index a3ca43124..a5e6cfc9d 100644 --- a/app/controllers/users/dossiers_controller.rb +++ b/app/controllers/users/dossiers_controller.rb @@ -16,7 +16,8 @@ module Users before_action :store_user_location!, only: :new def index - @user_dossiers = current_user.dossiers.includes(:procedure).order_by_updated_at.page(page) + @user_dossiers = current_user.dossiers.includes(:procedure).not_termine.order_by_updated_at.page(page) + @dossiers_traites = current_user.dossiers.includes(:procedure).termine.not_hidden_by_user.order_by_updated_at.page(page) @dossiers_invites = current_user.dossiers_invites.includes(:procedure).order_by_updated_at.page(page) @dossiers_supprimes = current_user.deleted_dossiers.order_by_updated_at.page(page) @dossier_transfers = DossierTransfer @@ -25,7 +26,7 @@ module Users .where(email: current_user.email) .page(page) @dossiers_close_to_expiration = current_user.dossiers.close_to_expiration.page(page) - @statut = statut(@user_dossiers, @dossiers_invites, @dossiers_supprimes, @dossier_transfers, @dossiers_close_to_expiration, params[:statut]) + @statut = statut(@user_dossiers, @dossiers_traites, @dossiers_invites, @dossiers_supprimes, @dossier_transfers, @dossiers_close_to_expiration, params[:statut]) end def show @@ -287,14 +288,22 @@ module Users @transfer = DossierTransfer.new(dossiers: current_user.dossiers) end + def hide_dossier + dossier = current_user.dossiers.includes(:user, procedure: :administrateurs).find(params[:id]) + dossier.update(hidden_by_user_at: Time.zone.now) + flash.notice = t('users.dossiers.ask_deletion.deleted_dossier') + redirect_to dossiers_path + end + private # if the status tab is filled, then this tab # else first filled tab - # else mes-dossiers - def statut(mes_dossiers, dossiers_invites, dossiers_supprimes, dossier_transfers, dossiers_close_to_expiration, params_statut) + # else en-cours + def statut(mes_dossiers, dossiers_traites, dossiers_invites, dossiers_supprimes, dossier_transfers, dossiers_close_to_expiration, params_statut) tabs = { - 'mes-dossiers' => mes_dossiers.present?, + 'en-cours' => mes_dossiers.present?, + 'traites' => dossiers_traites.present?, 'dossiers-invites' => dossiers_invites.present?, 'dossiers-supprimes' => dossiers_supprimes.present?, 'dossiers-transferes' => dossier_transfers.present?, @@ -306,7 +315,7 @@ module Users tabs .filter { |_tab, filled| filled } .map { |tab, _| tab } - .first || 'mes-dossiers' + .first || 'en-cours' end end diff --git a/app/models/dossier.rb b/app/models/dossier.rb index 12dd9b761..b4144c366 100644 --- a/app/models/dossier.rb +++ b/app/models/dossier.rb @@ -16,6 +16,7 @@ # en_instruction_at :datetime # groupe_instructeur_updated_at :datetime # hidden_at :datetime +# hidden_by_user_at :datetime # identity_updated_at :datetime # last_avis_updated_at :datetime # last_champ_private_updated_at :datetime @@ -206,9 +207,11 @@ class Dossier < ApplicationRecord scope :state_en_construction_ou_instruction, -> { where(state: EN_CONSTRUCTION_OU_INSTRUCTION) } scope :state_instruction_commencee, -> { where(state: INSTRUCTION_COMMENCEE) } scope :state_termine, -> { where(state: TERMINE) } + scope :state_not_termine, -> { where.not(state: TERMINE) } scope :archived, -> { where(archived: true) } scope :not_archived, -> { where(archived: false) } + scope :not_hidden_by_user, -> { where(hidden_by_user_at: nil) } scope :order_by_updated_at, -> (order = :desc) { order(updated_at: order) } scope :order_by_created_at, -> (order = :asc) { order(en_construction_at: order, created_at: order, id: order) } @@ -229,6 +232,7 @@ class Dossier < ApplicationRecord scope :en_construction, -> { not_archived.state_en_construction } scope :en_instruction, -> { not_archived.state_en_instruction } scope :termine, -> { not_archived.state_termine } + scope :not_termine, -> { state_not_termine } scope :processed_in_month, -> (month) do state_termine .joins(:traitements) @@ -1091,6 +1095,10 @@ class Dossier < ApplicationRecord end end + def hidden_by_user? + self.hidden_by_user_at.present? + end + private def create_missing_traitemets diff --git a/app/services/dossier_projection_service.rb b/app/services/dossier_projection_service.rb index c88c5a7e9..bb03493ba 100644 --- a/app/services/dossier_projection_service.rb +++ b/app/services/dossier_projection_service.rb @@ -1,5 +1,5 @@ class DossierProjectionService - class DossierProjection < Struct.new(:dossier_id, :state, :archived, :columns) + class DossierProjection < Struct.new(:dossier_id, :state, :archived, :hidden_by_user_at, :columns) end TABLE = 'table' @@ -20,8 +20,9 @@ class DossierProjectionService def self.project(dossiers_ids, fields) state_field = { TABLE => 'self', COLUMN => 'state' } archived_field = { TABLE => 'self', COLUMN => 'archived' } + hidden_by_user_at_field = { TABLE => 'self', COLUMN => 'hidden_by_user_at' } - ([state_field, archived_field] + fields) # the view needs state and archived dossier attributes + ([state_field, archived_field, hidden_by_user_at_field] + fields) # the view needs state and archived dossier attributes .each { |f| f[:id_value_h] = {} } .group_by { |f| f[TABLE] } # one query per table .each do |table, fields| @@ -45,7 +46,7 @@ class DossierProjectionService .pluck(:id, *fields.map { |f| f[COLUMN].to_sym }) .each do |id, *columns| fields.zip(columns).each do |field, value| - if [state_field, archived_field].include?(field) + if [state_field, archived_field, hidden_by_user_at_field].include?(field) field[:id_value_h][id] = value else field[:id_value_h][id] = value&.strftime('%d/%m/%Y') # other fields are datetime @@ -98,6 +99,7 @@ class DossierProjectionService dossier_id, state_field[:id_value_h][dossier_id], archived_field[:id_value_h][dossier_id], + hidden_by_user_at_field[:id_value_h][dossier_id], fields.map { |f| f[:id_value_h][dossier_id] } ) end diff --git a/app/views/commencer/show.html.haml b/app/views/commencer/show.html.haml index 4eb4840a5..28d78643a 100644 --- a/app/views/commencer/show.html.haml +++ b/app/views/commencer/show.html.haml @@ -11,7 +11,7 @@ = link_to t('views.shared.account.already_user'), commencer_sign_in_path(path: @procedure.path), class: ['button large expand'] - else - - dossiers = current_user.dossiers.where(revision: @revision.draft? ? @revision : @procedure.revisions.where.not(id: @procedure.draft_revision_id)) + - dossiers = current_user.dossiers.where(hidden_by_user_at: nil, revision: @revision.draft? ? @revision : @procedure.revisions.where.not(id: @procedure.draft_revision_id)) - drafts = dossiers.merge(Dossier.state_brouillon) - not_drafts = dossiers.merge(Dossier.state_not_brouillon) diff --git a/app/views/instructeurs/procedures/show.html.haml b/app/views/instructeurs/procedures/show.html.haml index 15d32e1fb..1ab6d2f62 100644 --- a/app/views/instructeurs/procedures/show.html.haml +++ b/app/views/instructeurs/procedures/show.html.haml @@ -100,8 +100,7 @@ %tbody - @projected_dossiers.each do |p| - path = instructeur_dossier_path(@procedure, p.dossier_id) - - %tr + %tr{ class: [p.hidden_by_user_at.present? && "file-hidden-by-user"] } %td.folder-col %a.cell-link{ href: path } %span.icon.folder @@ -113,7 +112,9 @@ - p.columns.each do |column| %td - %a.cell-link{ href: path }= column + %a.cell-link{ href: path } + = column + = "- #{t('views.instructeurs.dossiers.deleted_by_user')}" if p.hidden_by_user_at.present? %td.status-col %a.cell-link{ href: path }= status_badge(p.state) diff --git a/app/views/users/dossiers/_dossier_actions.html.haml b/app/views/users/dossiers/_dossier_actions.html.haml index 27f39af37..6e510222d 100644 --- a/app/views/users/dossiers/_dossier_actions.html.haml +++ b/app/views/users/dossiers/_dossier_actions.html.haml @@ -2,7 +2,8 @@ - has_delete_action = dossier.can_be_deleted_by_user? - has_new_dossier_action = dossier.procedure.accepts_new_dossiers? - has_transfer_action = dossier.user == current_user -- has_actions = has_edit_action || has_delete_action || has_new_dossier_action || has_transfer_action +- has_hide_action = dossier.termine? && dossier.hidden_by_user_at.nil? +- has_actions = has_edit_action || has_delete_action || has_new_dossier_action || has_transfer_action || has_hide_action - if has_actions .dropdown.user-dossier-actions @@ -44,3 +45,10 @@ %span.icon.delete .dropdown-description = t('views.users.dossiers.dossier_action.delete_dossier') + - if has_hide_action + %li + = link_to hide_dossier_dossier_path(dossier), method: :patch do + %span.icon.delete + .dropdown-description + = t('views.users.dossiers.dossier_action.hide_dossier') + diff --git a/app/views/users/dossiers/index.html.haml b/app/views/users/dossiers/index.html.haml index bebc753a8..2129ef487 100644 --- a/app/views/users/dossiers/index.html.haml +++ b/app/views/users/dossiers/index.html.haml @@ -15,25 +15,31 @@ - else %h1.page-title= t('views.users.dossiers.index.dossiers') %ul.tabs - - if @user_dossiers.count > 0 - = tab_item(t('pluralize.mes_dossiers', count: @user_dossiers.count), - dossiers_path(statut: 'mes-dossiers'), - active: @statut == 'mes-dossiers', + - if @user_dossiers.present? + = tab_item(t('pluralize.en_cours', count: @user_dossiers.count), + dossiers_path(statut: 'en-cours'), + active: @statut == 'en-cours', badge: number_with_html_delimiter(@user_dossiers.count)) - - if @dossiers_invites.count > 0 + - if @dossiers_traites.present? + = tab_item(t('pluralize.traites', count: @dossiers_traites.count), + dossiers_path(statut: 'traites'), + active: @statut == 'traites', + badge: number_with_html_delimiter(@dossiers_traites.count)) + + - if @dossiers_invites.present? = tab_item(t('pluralize.dossiers_invites', count: @dossiers_invites.count), dossiers_path(statut: 'dossiers-invites'), active: @statut == 'dossiers-invites', badge: number_with_html_delimiter(@dossiers_invites.count)) - - if @dossiers_supprimes.count > 0 + - if @dossiers_supprimes.present? = tab_item(t('pluralize.dossiers_supprimes', count: @dossiers_supprimes.count), dossiers_path(statut: 'dossiers-supprimes'), active: @statut == 'dossiers-supprimes', badge: number_with_html_delimiter(@dossiers_supprimes.count)) - - if @dossier_transfers.count > 0 + - if @dossier_transfers.present? = tab_item(t('pluralize.dossiers_transferes', count: @dossier_transfers.count), dossiers_path(statut: 'dossiers-transferes'), active: @statut == 'dossiers-transferes', @@ -46,9 +52,12 @@ badge: number_with_html_delimiter(@dossiers_close_to_expiration.count)) .container - - if @statut == "mes-dossiers" + - if @statut == "en-cours" = render partial: "dossiers_list", locals: { dossiers: @user_dossiers } + - if @statut == "traites" + = render partial: "dossiers_list", locals: { dossiers: @dossiers_traites } + - if @statut == "dossiers-invites" = render partial: "dossiers_list", locals: { dossiers: @dossiers_invites } diff --git a/config/locales/en.yml b/config/locales/en.yml index 713f9a6b9..875000695 100644 --- a/config/locales/en.yml +++ b/config/locales/en.yml @@ -132,6 +132,9 @@ en: form: "Form" edit_siret: "Edit SIRET" edit_identity: "Edit identity data" + instructeurs: + dossiers: + deleted_by_user: "File deleted by user" users: dossiers: autosave: @@ -191,6 +194,7 @@ en: edit_dossier: "Edit the file" start_other_dossier: "Start an other file" delete_dossier: "Delete the file" + hide_dossier: "Delete from your screen" transfer_dossier: "Transfer the file" edit_draft: "Edit the draft" actions: "Actions" @@ -326,10 +330,14 @@ en: zero: archived one: archived other: archived - mes_dossiers: - zero: my file - one: my file - other: my files + en_cours: + zero: in progress + one: in progress + other: in progress + traites: + zero: finished + one: finished + other: finished dossiers_invites: zero: guest file one: guest file diff --git a/config/locales/fr.yml b/config/locales/fr.yml index 7851bb7b4..5196e8aab 100644 --- a/config/locales/fr.yml +++ b/config/locales/fr.yml @@ -128,6 +128,9 @@ fr: form: "Formulaire" edit_siret: "Modifier le SIRET" edit_identity: "Modifier l’identité" + instructeurs: + dossiers: + deleted_by_user: "Dossier supprimé par l'usager" users: dossiers: autosave: @@ -187,6 +190,7 @@ fr: edit_dossier: "Modifier le dossier" start_other_dossier: "Commencer un autre dossier" delete_dossier: "Supprimer le dossier" + hide_dossier: "Supprimer de votre interface" transfer_dossier: "Transferer le dossier" edit_draft: "Modifier le brouillon" actions: "Actions" @@ -334,10 +338,14 @@ fr: zero: archivé one: archivé other: archivés - mes_dossiers: - zero: mon dossier - one: mon dossier - other: mes dossiers + en_cours: + zero: en cours + one: en cours + other: en cours + traites: + zero: traité + one: traité + other: traités dossiers_invites: zero: dossier invité one: dossier invité diff --git a/config/routes.rb b/config/routes.rb index 51117675b..30df3ec00 100644 --- a/config/routes.rb +++ b/config/routes.rb @@ -268,6 +268,7 @@ Rails.application.routes.draw do get 'messagerie' post 'commentaire' => 'dossiers#create_commentaire' post 'ask_deletion' + patch 'hide_dossier' get 'attestation' get 'transferer', to: 'dossiers#transferer' end diff --git a/db/migrate/20211110095853_add_hide_by_user_at_on_dossiers.rb b/db/migrate/20211110095853_add_hide_by_user_at_on_dossiers.rb new file mode 100644 index 000000000..9e7aa12b5 --- /dev/null +++ b/db/migrate/20211110095853_add_hide_by_user_at_on_dossiers.rb @@ -0,0 +1,5 @@ +class AddHideByUserAtOnDossiers < ActiveRecord::Migration[6.1] + def change + add_column :dossiers, :hidden_by_user_at, :datetime + end +end diff --git a/db/schema.rb b/db/schema.rb index c4625c91d..748e91ff5 100644 --- a/db/schema.rb +++ b/db/schema.rb @@ -324,6 +324,7 @@ ActiveRecord::Schema.define(version: 2021_11_24_111429) do t.bigint "dossier_transfer_id" t.datetime "identity_updated_at" t.datetime "depose_at" + t.datetime "hidden_by_user_at" t.index ["archived"], name: "index_dossiers_on_archived" t.index ["dossier_transfer_id"], name: "index_dossiers_on_dossier_transfer_id" t.index ["groupe_instructeur_id"], name: "index_dossiers_on_groupe_instructeur_id" diff --git a/spec/controllers/users/dossiers_controller_spec.rb b/spec/controllers/users/dossiers_controller_spec.rb index 75a0dcfb3..b9a60f226 100644 --- a/spec/controllers/users/dossiers_controller_spec.rb +++ b/spec/controllers/users/dossiers_controller_spec.rb @@ -793,14 +793,14 @@ describe Users::DossiersController, type: :controller do context 'when the user does not have any dossiers' do before { get(:index) } - it { expect(assigns(:statut)).to eq('mes-dossiers') } + it { expect(assigns(:statut)).to eq('en-cours') } end context 'when the user only have its own dossiers' do let!(:own_dossier) { create(:dossier, user: user) } before { get(:index) } - it { expect(assigns(:statut)).to eq('mes-dossiers') } + it { expect(assigns(:statut)).to eq('en-cours') } it { expect(assigns(:user_dossiers)).to match([own_dossier]) } end @@ -813,14 +813,16 @@ describe Users::DossiersController, type: :controller do it { expect(assigns(:dossiers_invites)).to match([invite.dossier]) } end - context 'when the user has both' do + context 'when the user has dossiers invites, own and traites' do + let!(:procedure) { create(:procedure, :published) } let!(:own_dossier) { create(:dossier, user: user) } + let!(:own_dossier2) { create(:dossier, user: user, state: "accepte", procedure: procedure) } let!(:invite) { create(:invite, dossier: create(:dossier), user: user) } context 'and there is no statut param' do before { get(:index) } - it { expect(assigns(:statut)).to eq('mes-dossiers') } + it { expect(assigns(:statut)).to eq('en-cours') } end context 'and there is "dossiers-invites" param' do @@ -829,10 +831,24 @@ describe Users::DossiersController, type: :controller do it { expect(assigns(:statut)).to eq('dossiers-invites') } end - context 'and there is "mes-dossiers" param' do - before { get(:index, params: { statut: 'mes-dossiers' }) } + context 'and there is "en-cours" param' do + before { get(:index, params: { statut: 'en-cours' }) } - it { expect(assigns(:statut)).to eq('mes-dossiers') } + it { expect(assigns(:statut)).to eq('en-cours') } + end + + context 'and there is "traites" param' do + before { get(:index, params: { statut: 'traites' }) } + + it { expect(assigns(:statut)).to eq('traites') } + end + + context 'and the traité dossier has been hidden by user' do + before do + own_dossier2.update!(hidden_by_user_at: Time.zone.now) + get(:index, params: { statut: 'traites' }) + end + it { expect(assigns(:statut)).to eq('en-cours') } end end diff --git a/spec/views/users/dossiers/_dossier_actions.html.haml_spec.rb b/spec/views/users/dossiers/_dossier_actions.html.haml_spec.rb index c4512b41e..0859ea60f 100644 --- a/spec/views/users/dossiers/_dossier_actions.html.haml_spec.rb +++ b/spec/views/users/dossiers/_dossier_actions.html.haml_spec.rb @@ -18,14 +18,4 @@ describe 'users/dossiers/dossier_actions.html.haml', type: :view do let(:procedure) { create(:procedure, :closed) } it { is_expected.not_to have_link('Commencer un autre dossier') } end - - context 'when there are no actions to display' do - let(:procedure) { create(:procedure, :closed) } - let(:dossier) { create(:dossier, :accepte, procedure: procedure) } - let(:user) { create(:user) } - - it 'doesn’t render the menu at all' do - expect(subject).not_to have_selector('.dropdown') - end - end end diff --git a/spec/views/users/dossiers/index.html.haml_spec.rb b/spec/views/users/dossiers/index.html.haml_spec.rb index 2764bb99c..ce5d4c7f1 100644 --- a/spec/views/users/dossiers/index.html.haml_spec.rb +++ b/spec/views/users/dossiers/index.html.haml_spec.rb @@ -2,9 +2,10 @@ describe 'users/dossiers/index.html.haml', type: :view do let(:user) { create(:user) } let(:dossier_brouillon) { create(:dossier, state: Dossier.states.fetch(:brouillon), user: user) } let(:dossier_en_construction) { create(:dossier, state: Dossier.states.fetch(:en_construction), user: user) } - let(:user_dossiers) { [dossier_brouillon, dossier_en_construction] } + let(:dossier_termine) { create(:dossier, state: Dossier.states.fetch(:accepte), user: user) } + let(:user_dossiers) { [dossier_brouillon, dossier_en_construction, dossier_termine] } let(:dossiers_invites) { [] } - let(:statut) { 'mes-dossiers' } + let(:statut) { 'en-cours' } before do allow(view).to receive(:new_demarche_url).and_return('#') @@ -12,6 +13,7 @@ describe 'users/dossiers/index.html.haml', type: :view do assign(:user_dossiers, Kaminari.paginate_array(user_dossiers).page(1)) assign(:dossiers_invites, Kaminari.paginate_array(dossiers_invites).page(1)) assign(:dossiers_supprimes, Kaminari.paginate_array(user_dossiers).page(1)) + assign(:dossiers_traites, Kaminari.paginate_array(user_dossiers).page(1)) assign(:dossier_transfers, Kaminari.paginate_array([]).page(1)) assign(:dossiers_close_to_expiration, Kaminari.paginate_array([]).page(1)) assign(:statut, statut) @@ -19,7 +21,7 @@ describe 'users/dossiers/index.html.haml', type: :view do end it 'affiche la liste des dossiers' do - expect(rendered).to have_selector('.dossiers-table tbody tr', count: 2) + expect(rendered).to have_selector('.dossiers-table tbody tr', count: 3) end it 'affiche les informations des dossiers' do @@ -67,8 +69,16 @@ describe 'users/dossiers/index.html.haml', type: :view do it 'affiche la barre d’onglets' do expect(rendered).to have_selector('ul.tabs') - expect(rendered).to have_selector('ul.tabs li', count: 3) + expect(rendered).to have_selector('ul.tabs li', count: 4) expect(rendered).to have_selector('ul.tabs li.active', count: 1) end end + + context 'where there is a traite dossier' do + let(:dossiers_traites) { create_list(:dossier, 1) } + + it "displays the hide by user at button" do + expect(rendered).to have_text("Supprimer le dossier") + end + end end