Skip to content

Commit

Permalink
Merge pull request #11193 from demarches-simplifiees/fix-10788
Browse files Browse the repository at this point in the history
ETQ instructeur, sur la liste des démarches, je peux accéder directement à une démarche via une dropdown
  • Loading branch information
LeSim authored Feb 20, 2025
2 parents cd173b2 + 94e1a7d commit ac46797
Show file tree
Hide file tree
Showing 12 changed files with 162 additions and 7 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
# frozen_string_literal: true

class Instructeurs::SelectProcedureDropDownListComponent < Dsfr::InputComponent
def initialize(procedures:)
@procedures = procedures
end

def render?
@procedures.count > 3
end

def react_props
{
items:,
placeholder: t('.placeholder'),
name: "procedure_id",
id: 'select-procedure-drop-down-list',
'aria-describedby': 'select-procedure-drop-down-list-label',
form: 'select-procedure-drop-down-list-component',
data: { no_autosubmit: 'input blur', no_autosubmit_on_empty: 'true', autosubmit_target: 'input' }
}
end

def items
@procedures.map { ["n°#{_1.id} - #{_1.libelle}", _1.id] }
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
---
en:
label: Direct access
placeholder: Select a procedure
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
---
fr:
label: Accès direct
placeholder: Sélectionner une démarche
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
= form_with url: url_for([:select_procedure, :instructeur, :procedures]),
class: 'ml-auto',
id: 'select-procedure-drop-down-list-component',
data: { turbo: false, controller: 'autosubmit' } do

.flex.align-center
= label_tag :procedure_id, t('.label'), class: 'fr-label font-weight-bold fr-mr-2w', id: 'select-procedure-drop-down-list-label', for: 'select-procedure-drop-down-list'
%react-fragment
= render ReactComponent.new "ComboBox/SingleComboBox", **react_props

%input.hidden{
type: 'submit',
formmethod: 'get',
formaction: url_for([:select_procedure, :instructeur, :procedures]),
formnovalidate: 'true',
data: { autosubmit_target: 'submitter' }
}
8 changes: 7 additions & 1 deletion app/controllers/instructeurs/procedures_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

module Instructeurs
class ProceduresController < InstructeurController
before_action :ensure_ownership!, except: [:index, :order_positions, :update_order_positions]
before_action :ensure_ownership!, except: [:index, :order_positions, :update_order_positions, :select_procedure]
before_action :ensure_not_super_admin!, only: [:download_export, :exports]

ITEMS_PER_PAGE = 100
Expand Down Expand Up @@ -74,6 +74,12 @@ def update_order_positions
redirect_to instructeur_procedures_path, notice: "L'ordre des démarches a été mis à jour."
end

def select_procedure
return redirect_to instructeur_procedure_path(procedure_id: params[:procedure_id]) if params[:procedure_id].present?

redirect_to instructeur_procedures_path
end

def show
@procedure = procedure
# Technically, procedure_presentation already sets the attribute.
Expand Down
11 changes: 10 additions & 1 deletion app/javascript/components/ComboBox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,12 @@ export function ComboBox({
inputRef,
isLoading,
isOpen,
placeholder,
...props
}: ComboBoxProps & {
inputRef?: RefObject<HTMLInputElement>;
isOpen?: boolean;
placeholder?: string;
}) {
return (
<AriaComboBox
Expand All @@ -69,6 +71,7 @@ export function ComboBox({
className="fr-select fr-autocomplete"
ref={inputRef}
aria-busy={isLoading}
placeholder={placeholder || undefined}
/>
<Button
aria-haspopup="false"
Expand Down Expand Up @@ -107,6 +110,7 @@ export function SingleComboBox({
const {
items: defaultItems,
selectedKey: defaultSelectedKey,
placeholder,
emptyFilterKey,
name,
formValue,
Expand All @@ -128,7 +132,12 @@ export function SingleComboBox({

return (
<>
<ComboBox menuTrigger="focus" {...comboBoxProps} {...props}>
<ComboBox
menuTrigger="focus"
placeholder={placeholder}
{...comboBoxProps}
{...props}
>
{(item) => <ComboBoxItem id={item.value}>{item.label}</ComboBoxItem>}
</ComboBox>
{children || name ? (
Expand Down
8 changes: 3 additions & 5 deletions app/javascript/components/react-aria/props.ts
Original file line number Diff line number Diff line change
Expand Up @@ -14,10 +14,7 @@ const ArrayOfTuples = s.coerce(
s.array(Item),
s.array(s.tuple([s.string(), s.union([s.string(), s.number()])])),
(items) =>
items.map<Item>(([label, value]) => ({
label,
value: String(value)
}))
items.map<Item>(([label, value]) => ({ label, value: String(value) }))
);

const ArrayOfStrings = s.coerce(s.array(Item), s.array(s.string()), (items) =>
Expand Down Expand Up @@ -47,7 +44,8 @@ export const SingleComboBoxProps = s.assign(
s.object({
selectedKey: s.nullable(s.string()),
emptyFilterKey: s.nullable(s.string()),
maxItemsDisplay: s.number()
maxItemsDisplay: s.number(),
placeholder: s.string()
})
)
);
Expand Down
1 change: 1 addition & 0 deletions app/views/instructeurs/procedures/index.html.haml
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
.flex.fr-mb-2v
%h1.fr-h3.fr-mb-0 Démarches
= render Instructeurs::TabsExplanationsComponent.new
= render Instructeurs::SelectProcedureDropDownListComponent.new(procedures: @procedures)
= render partial: 'instructeurs/procedures/synthese', locals: { procedures: @procedures, all_dossiers_counts: @all_dossiers_counts }

%nav.fr-tabs{ role: 'navigation', 'aria-label': t('views.users.dossiers.secondary_menu') }
Expand Down
1 change: 1 addition & 0 deletions config/routes.rb
Original file line number Diff line number Diff line change
Expand Up @@ -461,6 +461,7 @@
collection do
get 'order_positions'
patch 'update_order_positions'
get 'select_procedure'
end
end

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,37 @@
# frozen_string_literal: true

require "rails_helper"

RSpec.describe Instructeurs::SelectProcedureDropDownListComponent, type: :component do
subject do
render_inline(described_class.new(procedures:))
end

let(:procedures) {
[
create(:procedure, libelle: "Procedure importante", id: 1001),
create(:procedure, libelle: "Procedure facile", id: 1002),
create(:procedure, libelle: "Procedure terminée", id: 1003),
create(:procedure, libelle: "Procedure terminée 2", id: 1004),
create(:procedure, libelle: "Procedure terminée 3", id: 1005)
]
}

it "renders the label" do
expect(subject).to have_text("Accès direct")
end

let(:react_component) { page.find('react-component') }
let(:react_props_items) { JSON.parse(react_component['props']) }

it "renders the procedures" do
subject
expect(react_props_items["items"]).to eq([
["n°1001 - Procedure importante", 1001],
["n°1002 - Procedure facile", 1002],
["n°1003 - Procedure terminée", 1003],
["n°1004 - Procedure terminée 2", 1004],
["n°1005 - Procedure terminée 3", 1005]
])
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# frozen_string_literal: true

class Instructeurs::SelectProcedureDropDownListComponentPreview < ViewComponent::Preview
def default
@procedures = Procedure.limit(10)
render(Instructeurs::SelectProcedureDropDownListComponent.new(procedures: @procedures))
end
end
43 changes: 43 additions & 0 deletions spec/controllers/instructeurs/procedures_controller_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -1017,4 +1017,47 @@
expect(response.body).not_to include("Déposer")
end
end

describe '#select_procedure' do
let(:instructeur) { create(:instructeur) }

before do
sign_in(instructeur.user)
end

context 'when procedure_id is present' do
let(:procedure) { create(:procedure) }

it 'redirects to the procedure path' do
puts "procedure.id: #{procedure.id}"
get :select_procedure, params: { procedure_id: procedure.id }

expect(response).to redirect_to(instructeur_procedure_path(procedure_id: procedure.id))
end
end

context 'when procedure_id is not present' do
it 'redirects to procedures index' do
get :select_procedure

expect(response).to redirect_to(instructeur_procedures_path)
end
end

context 'when procedure_id is empty string' do
it 'redirects to procedures index' do
get :select_procedure, params: { procedure_id: '' }

expect(response).to redirect_to(instructeur_procedures_path)
end
end

context 'when procedure_id is nil' do
it 'redirects to procedures index' do
get :select_procedure, params: { procedure_id: nil }

expect(response).to redirect_to(instructeur_procedures_path)
end
end
end
end

0 comments on commit ac46797

Please sign in to comment.