diff --git a/app/assets/stylesheets/procedure_show.scss b/app/assets/stylesheets/procedure_show.scss index c37894953..660a77d14 100644 --- a/app/assets/stylesheets/procedure_show.scss +++ b/app/assets/stylesheets/procedure_show.scss @@ -103,6 +103,11 @@ border-color: $blue-france-500; } } + + // fix/dsfr + .fr-checkbox-group.fix-dsfr-notified-toggle-component { + margin-top: -7px; + } } ul.revision-changes { diff --git a/app/assets/stylesheets/utils.scss b/app/assets/stylesheets/utils.scss index 0f7279e9c..66d9da5d6 100644 --- a/app/assets/stylesheets/utils.scss +++ b/app/assets/stylesheets/utils.scss @@ -18,6 +18,18 @@ display: inline; } +.visually-hidden { + position: absolute; + width: 1px; + height: 1px; + padding: 0; + margin: -1px; + overflow: hidden; + clip: rect(0, 0, 0, 0); + white-space: nowrap; + border: none; +} + // text .text-center, .center { diff --git a/app/components/dossiers/notified_toggle_component.rb b/app/components/dossiers/notified_toggle_component.rb new file mode 100644 index 000000000..f794c4288 --- /dev/null +++ b/app/components/dossiers/notified_toggle_component.rb @@ -0,0 +1,41 @@ +class Dossiers::NotifiedToggleComponent < ApplicationComponent + def initialize(procedure:, procedure_presentation:) + @procedure = procedure + @procedure_presentation = procedure_presentation + @current_sort = procedure_presentation.sort + end + + private + + def opposite_order + @procedure_presentation.opposite_order_for(current_table, current_column) + end + + def active? + sorted_by_notifications? && order_asc? + end + + def icon_class_name + active? ? 'fr-fi-checkbox' : 'fr-fi-checkbox-blank' + end + + def order_asc? + current_order == 'asc' + end + + def current_order + @current_sort['order'] + end + + def current_table + @current_sort['table'] + end + + def current_column + @current_sort['column'] + end + + def sorted_by_notifications? + current_table == 'notifications' && current_column == 'notifications' + end +end diff --git a/app/components/dossiers/notified_toggle_component/notified_toggle_component.en.yml b/app/components/dossiers/notified_toggle_component/notified_toggle_component.en.yml new file mode 100644 index 000000000..7c4eeadc2 --- /dev/null +++ b/app/components/dossiers/notified_toggle_component/notified_toggle_component.en.yml @@ -0,0 +1,2 @@ +en: + show_notified_first: Show files with notification first diff --git a/app/components/dossiers/notified_toggle_component/notified_toggle_component.fr.yml b/app/components/dossiers/notified_toggle_component/notified_toggle_component.fr.yml new file mode 100644 index 000000000..05f2025e1 --- /dev/null +++ b/app/components/dossiers/notified_toggle_component/notified_toggle_component.fr.yml @@ -0,0 +1,2 @@ +fr: + show_notified_first: Remonter les dossiers avec une notification diff --git a/app/components/dossiers/notified_toggle_component/notified_toggle_component.html.haml b/app/components/dossiers/notified_toggle_component/notified_toggle_component.html.haml new file mode 100644 index 000000000..3a8a2dfb7 --- /dev/null +++ b/app/components/dossiers/notified_toggle_component/notified_toggle_component.html.haml @@ -0,0 +1,7 @@ += form_tag update_sort_instructeur_procedure_path(procedure_id: @procedure.id, table: 'notifications', column: 'notifications', order: opposite_order), method: 'GET', data: {controller: 'checkbox'} do + .fr-form-group + .fr-fieldset__content + .fr-checkbox-group.fix-dsfr-notified-toggle-component + = check_box_tag :order, opposite_order, active?, data: {action: 'change->checkbox#onChange'} + = label_tag :order, t('.show_notified_first'), class: 'fr-label' + = submit_tag t('.show_notified_first'), data: {"checkbox-target": 'submit' }, class: 'visually-hidden' diff --git a/app/controllers/instructeurs/procedures_controller.rb b/app/controllers/instructeurs/procedures_controller.rb index 121db3010..48b6fd787 100644 --- a/app/controllers/instructeurs/procedures_controller.rb +++ b/app/controllers/instructeurs/procedures_controller.rb @@ -121,7 +121,7 @@ module Instructeurs end def update_sort - procedure_presentation.update_sort(params[:table], params[:column]) + procedure_presentation.update_sort(params[:table], params[:column], params[:order]) redirect_back(fallback_location: instructeur_procedure_url(procedure)) end diff --git a/app/javascript/controllers/checkbox_controller.ts b/app/javascript/controllers/checkbox_controller.ts new file mode 100644 index 000000000..8b85bb51b --- /dev/null +++ b/app/javascript/controllers/checkbox_controller.ts @@ -0,0 +1,8 @@ +import { ApplicationController } from './application_controller'; + +export class CheckboxController extends ApplicationController { + onChange() { + const form = this.element as HTMLFormElement; + form.requestSubmit(); + } +} diff --git a/app/javascript/entrypoints/main.css b/app/javascript/entrypoints/main.css index 8b41500dd..d9bd726bf 100644 --- a/app/javascript/entrypoints/main.css +++ b/app/javascript/entrypoints/main.css @@ -14,6 +14,7 @@ @import '@gouvfr/dsfr/dist/component/connect/connect.css'; @import '@gouvfr/dsfr/dist/component/highlight/highlight.css'; @import '@gouvfr/dsfr/dist/component/input/input.css'; +@import '@gouvfr/dsfr/dist/component/checkbox/checkbox.css'; @import '@gouvfr/dsfr/dist/component/logo/logo.css'; @import '@gouvfr/dsfr/dist/component/modal/modal.css'; @import '@gouvfr/dsfr/dist/component/navigation/navigation.css'; diff --git a/app/models/procedure_presentation.rb b/app/models/procedure_presentation.rb index c51999419..7b5ac387f 100644 --- a/app/models/procedure_presentation.rb +++ b/app/models/procedure_presentation.rb @@ -18,6 +18,8 @@ class ProcedurePresentation < ApplicationRecord TABLE = 'table' COLUMN = 'column' + ORDER = 'order' + SLASH = '/' TYPE_DE_CHAMP = 'type_de_champ' TYPE_DE_CHAMP_PRIVATE = 'type_de_champ_private' @@ -286,18 +288,20 @@ class ProcedurePresentation < ApplicationRecord end end - def update_sort(table, column) - order = if sort.values_at(TABLE, COLUMN) == [table, column] + def update_sort(table, column, order) + update!(sort: { + TABLE => table, + COLUMN => column, + ORDER => opposite_order_for(table, column) + }) + end + + def opposite_order_for(table, column) + if sort.values_at(TABLE, COLUMN) == [table, column] sort['order'] == 'asc' ? 'desc' : 'asc' else 'asc' end - - update!(sort: { - TABLE => table, - COLUMN => column, - 'order' => order - }) end def snapshot diff --git a/app/views/instructeurs/procedures/_header_field.html.haml b/app/views/instructeurs/procedures/_header_field.html.haml index 5ef47b161..5d852a592 100644 --- a/app/views/instructeurs/procedures/_header_field.html.haml +++ b/app/views/instructeurs/procedures/_header_field.html.haml @@ -1,5 +1,5 @@ %th{ class: classname } - = link_to update_sort_instructeur_procedure_path(@procedure, table: field['table'], column: field['column']) do + = link_to update_sort_instructeur_procedure_path(@procedure, table: field['table'], column: field['column'], order: @procedure_presentation.opposite_order_for(field['table'], field['column'])) do - if @procedure_presentation.sort['table'] == field['table'] && @procedure_presentation.sort['column'] == field['column'] - if @procedure_presentation.sort['order'] == 'asc' #{field['label']} ↑ diff --git a/app/views/instructeurs/procedures/show.html.haml b/app/views/instructeurs/procedures/show.html.haml index aea92a284..1ea7b6df5 100644 --- a/app/views/instructeurs/procedures/show.html.haml +++ b/app/views/instructeurs/procedures/show.html.haml @@ -63,6 +63,8 @@ .flex .flex-grow = render partial: "dossiers_filter", locals: { procedure: @procedure, procedure_presentation: @procedure_presentation, current_filters: @current_filters, statut: @statut, filterable_fields_for_select: @filterable_fields_for_select } + .flex-grow + = render Dossiers::NotifiedToggleComponent.new(procedure: @procedure, procedure_presentation: @procedure_presentation) - if @dossiers_count > 0 .dossiers-export = render Dossiers::ExportComponent.new(procedure: @procedure, exports: @exports, statut: @statut, count: @dossiers_count, export_url: method(:download_export_instructeur_procedure_path)) diff --git a/spec/system/instructeurs/procedure_sort_spec.rb b/spec/system/instructeurs/procedure_sort_spec.rb new file mode 100644 index 000000000..358d1ca8d --- /dev/null +++ b/spec/system/instructeurs/procedure_sort_spec.rb @@ -0,0 +1,43 @@ +describe "procedure sort" do + let(:instructeur) { create(:instructeur) } + let(:procedure) { create(:procedure, :published, :with_type_de_champ, instructeurs: [instructeur]) } + let!(:new_unfollow_dossier) { create(:dossier, procedure: procedure, state: Dossier.states.fetch(:en_instruction)) } + let!(:followed_dossier) { create(:dossier, procedure: procedure, state: Dossier.states.fetch(:en_instruction)) } + let!(:new_unfollow_dossier_2) { create(:dossier, procedure: procedure, state: Dossier.states.fetch(:en_instruction)) } + + before do + instructeur.follow(followed_dossier) + followed_dossier.champs.first.update(value: '123') + + login_as(instructeur.user, scope: :user) + visit instructeur_procedure_path(procedure) + end + + scenario "should be able to sort with header" do + all(".dossiers-table tbody tr:nth-child(1) .number-col a", text: new_unfollow_dossier_2.id) + all(".dossiers-table tbody tr:nth-child(2) .number-col a", text: followed_dossier.id) + all(".dossiers-table tbody tr:nth-child(3) .number-col a", text: new_unfollow_dossier.id) + + find("thead .number-col a").click # reverse id filter + + all(".dossiers-table tbody tr:nth-child(1) .number-col a", text: new_unfollow_dossier.id) + all(".dossiers-table tbody tr:nth-child(2) .number-col a", text: followed_dossier.id) + all(".dossiers-table tbody tr:nth-child(3) .number-col a", text: new_unfollow_dossier_2.id) + end + + scenario "should be able to sort with direct link to notificaiton filter" do + # dossier sorted by id + check "Remonter les dossiers avec une notification" + + # sort by notification + all(".dossiers-table tbody tr:nth-child(1) .number-col a", text: followed_dossier.id) + all(".dossiers-table tbody tr:nth-child(2) .number-col a", text: new_unfollow_dossier.id) + all(".dossiers-table tbody tr:nth-child(3) .number-col a", text: new_unfollow_dossier_2.id) + + uncheck "Remonter les dossiers avec une notification" + + all(".dossiers-table tbody tr:nth-child(1) .number-col a", text: new_unfollow_dossier_2.id) + all(".dossiers-table tbody tr:nth-child(2) .number-col a", text: followed_dossier.id) + all(".dossiers-table tbody tr:nth-child(3) .number-col a", text: new_unfollow_dossier.id) + end +end