feat(instructeur/procedure#show): enhance sort by notifications as planned by UX

Update app/javascript/controllers/checkbox_controller.ts

Co-authored-by: Paul Chavard <github@paul.chavard.net>
This commit is contained in:
Martin 2022-09-26 17:14:20 +02:00 committed by mfo
parent 400bc5207d
commit aceb8996c1
13 changed files with 137 additions and 10 deletions

View file

@ -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 {

View file

@ -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 {

View file

@ -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

View file

@ -0,0 +1,2 @@
en:
show_notified_first: Show files with notification first

View file

@ -0,0 +1,2 @@
fr:
show_notified_first: Remonter les dossiers avec une notification

View file

@ -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'

View file

@ -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

View file

@ -0,0 +1,8 @@
import { ApplicationController } from './application_controller';
export class CheckboxController extends ApplicationController {
onChange() {
const form = this.element as HTMLFormElement;
form.requestSubmit();
}
}

View file

@ -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';

View file

@ -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

View file

@ -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']} ↑

View file

@ -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))

View file

@ -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