Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
14 changes: 14 additions & 0 deletions app/assets/stylesheets/dsfr.scss
Original file line number Diff line number Diff line change
Expand Up @@ -310,6 +310,20 @@ input[type='radio'] {
box-shadow: none;
}

// Accordéons de la page suivi-et-décision
#suivi-et-decision .fr-accordion__btn {
color: var(--text-title-grey);
font-weight: bold;
}

#suivi-et-decision .fr-collapse--expanded {
padding-bottom: 3rem;
}

#suivi-et-decision .fr-collapse--expanded > :last-child {
margin-bottom: 0;
}

// Réduit le margin droit du toggle lorsqu'il n'y a pas de label associé
.fr-toggle.fr-toggle--no-label label::before {
margin-right: 0.5rem;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,7 +10,10 @@
</button>
<% end %>

<div id="<%= accordion_id %>" class="fr-collapse">
<div
id="<%= accordion_id %>"
class="fr-collapse<%= ' fr-collapse--expanded' if expanded %>"
>
<% if content? %>
<%= content %>
<% end %>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
en:
title: Events and decisions made
depose: "On %{processed_at}, this file was submitted"
depose_correction_usager: "On %{processed_at}, corrections were submitted"
depose_correction_instructeur: "On %{processed_at}, the instructor %{email} edited this file"
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
fr:
title: Événements et décisions rendues
depose: Le %{processed_at}, ce dossier a été déposé
depose_correction_usager: Le %{processed_at}, des corrections ont été déposées
depose_correction_instructeur: Le %{processed_at}, lʼinstructeur %{email} a modifié ce dossier
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,3 @@
<div class="tab-title"><%= t('.title') %></div>

<ul class="tab-list">
<% traitements.each do |traitement| %>
<li><%= t(".#{traitement.event}", **traitement_props(traitement)) %></li>
Expand Down
16 changes: 16 additions & 0 deletions app/components/instructeurs/envoyer_dossier_form_component.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# frozen_string_literal: true

class Instructeurs::EnvoyerDossierFormComponent < ApplicationComponent
attr_reader :dossier, :potential_recipients

def initialize(dossier:, potential_recipients:)
@dossier = dossier
@potential_recipients = potential_recipients
end

private

def recipient_items
potential_recipients.map { [it.email, it.id] }
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
en:
title: Send this file to another instructor
hint: The recipient will automatically follow the file
no_recipients: You are the only instructor assigned to this procedure
submit: Send
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
fr:
title: Envoyer ce dossier à un autre instructeur
hint: Le destinataire suivra automatiquement le dossier
no_recipients: Vous êtes le seul instructeur assigné sur cette démarche
submit: Envoyer
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<% if potential_recipients.empty? %>
<p><%= t(".title") %></p>
<p class="tab-paragraph"><%= t(".no_recipients") %></p>
<% else %>
<%= form_for dossier, url: send_to_instructeurs_instructeur_dossier_path(dossier.procedure, dossier), method: :post, html: { class: 'form recipients-form fr-mb-4w' } do |f| %>
<div class="fr-select-group">
<label class="fr-label fr-mb-1w" for="envoyer-dossier-select">
<span id="envoyer-dossier-label"><%= t(".title") %></span>
<span class="fr-hint-text"><%= t(".hint") %></span>
</label>

<div class="fr-grid-row fr-grid-row--gutters fr-grid-row--top">
<div class="fr-col-8">
<react-fragment>
<%= render ReactComponent.new "Select/MultipleSelect",
triggerId: 'envoyer-dossier-select',
'aria-labelledby': 'envoyer-dossier-label',
items: recipient_items,
name: 'recipients[]' %>
</react-fragment>
</div>

<div class="fr-col-4">
<%= f.submit t(".submit"), class: "fr-btn" %>
</div>
</div>
</div>
<% end %>
<% end %>
17 changes: 17 additions & 0 deletions app/components/instructeurs/reaffectation_form_component.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
# frozen_string_literal: true

class Instructeurs::ReaffectationFormComponent < ApplicationComponent
attr_reader :dossier, :groupe_instructeur, :groupes_instructeurs

def initialize(dossier:, groupe_instructeur:, groupes_instructeurs:)
@dossier = dossier
@groupe_instructeur = groupe_instructeur
@groupes_instructeurs = groupes_instructeurs
end

private

def group_items
groupes_instructeurs.map { |g| { label: g.label, value: g.id.to_s } }
end
end
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
en:
title: "Reassign the file n° %{dossier_id} to another group"
hint:
one: "This file is assigned to group « %{label} ». You can reassign it to the other group"
other: "This file is assigned to group « %{label} ». You can reassign it to one of the %{count} other groups"
submit: Reassign the file to this group
select: Select
confirm: "Are you sure you want to reassign the file n° %{dossier_id} from the group « %{label} »?"
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
fr:
title: "Réaffecter le dossier n° %{dossier_id} à un autre groupe instructeur"
hint:
one: "Ce dossier est affecté au groupe « %{label} ». Vous pouvez le réaffecter à lʼautre groupe instructeur"
other: "Ce dossier est affecté au groupe « %{label} ». Vous pouvez le réaffecter à lʼun des %{count} autres groupes instructeurs"
submit: Réaffecter le dossier à ce groupe
select: Sélectionner
confirm: "Êtes-vous sûr de vouloir réaffecter le dossier n° %{dossier_id} du groupe « %{label} » ?"
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
<div class="fr-mt-2w">
<%= form_with url: reaffecter_instructeur_dossier_path(procedure_id: dossier.procedure.id, dossier_id: dossier.id), method: :post, local: true, data: { controller: 'enable-submit-if-filled', action: 'change->enable-submit-if-filled#fillCombobox' } do |form| %>
<div class="fr-input-group">
<label class="fr-label fr-mb-1w" for="reaffectation-input">
<%= t(".title", dossier_id: dossier.id) %>

<span class="fr-hint-text">
<%= t(".hint", label: groupe_instructeur.label, count: groupes_instructeurs.count) %>
</span>
</label>

<div class="fr-grid-row fr-grid-row--gutters fr-grid-row--bottom">
<div class="fr-col-8">
<react-fragment>
<%= render ReactComponent.new "ComboBox/SingleComboBox",
inputId: 'reaffectation-input',
name: 'groupe_instructeur_id',
placeholder: t(".select"),
items: group_items,
data: { enable_submit_if_filled_target: 'input' } %>
</react-fragment>
</div>

<div class="fr-col-4">
<%= form.submit t(".submit"),
class: 'fr-btn',
data: { enable_submit_if_filled_target: 'submit', confirm: t(".confirm", dossier_id: dossier.id, label: groupe_instructeur.label) },
disabled: true %>
</div>
</div>
</div>
<% end %>
</div>
36 changes: 22 additions & 14 deletions app/controllers/instructeurs/dossiers_controller.rb
Original file line number Diff line number Diff line change
Expand Up @@ -17,9 +17,9 @@ class DossiersController < ProceduresController
before_action :redirect_on_dossier_in_batch_operation, only: [:archive, :unarchive, :follow, :unfollow, :passer_en_instruction, :repasser_en_construction, :repasser_en_instruction, :terminer, :restore, :destroy, :extend_conservation]
before_action :dossier_with_champs, only: [:show, :show_submitted_revision]
before_action :dossier_with_submitted_revision, only: [:show_submitted_revision]
before_action :set_gallery_attachments, only: [:show, :pieces_jointes, :annotations_privees, :avis, :messagerie, :personnes_impliquees, :reaffectation, :rendez_vous, :rdv_connection]
before_action :retrieve_procedure_presentation, only: [:annotations_privees, :avis_new, :avis, :messagerie, :personnes_impliquees, :pieces_jointes, :reaffectation, :rendez_vous, :rdv_connection, :show, :dossier_labels, :passer_en_instruction, :repasser_en_construction, :repasser_en_instruction, :terminer, :pending_correction, :create_avis, :create_commentaire]
before_action :set_notifications, only: [:show, :annotations_privees, :avis, :avis_new, :messagerie, :personnes_impliquees, :pieces_jointes, :reaffectation, :rendez_vous, :rdv_connection, :dossier_labels, :repasser_en_construction, :repasser_en_instruction, :create_avis, :create_commentaire]
before_action :set_gallery_attachments, only: [:show, :pieces_jointes, :annotations_privees, :avis, :messagerie, :suivi_et_decision, :rendez_vous, :rdv_connection]
before_action :retrieve_procedure_presentation, only: [:annotations_privees, :avis_new, :avis, :messagerie, :suivi_et_decision, :pieces_jointes, :rendez_vous, :rdv_connection, :show, :dossier_labels, :passer_en_instruction, :repasser_en_construction, :repasser_en_instruction, :terminer, :pending_correction, :create_avis, :create_commentaire]
before_action :set_notifications, only: [:show, :annotations_privees, :avis, :avis_new, :messagerie, :suivi_et_decision, :pieces_jointes, :rendez_vous, :rdv_connection, :dossier_labels, :repasser_en_construction, :repasser_en_instruction, :create_avis, :create_commentaire]

after_action :mark_demande_as_read, only: :show
after_action :mark_messagerie_as_read, only: [:messagerie, :create_commentaire, :pending_correction]
Expand Down Expand Up @@ -122,14 +122,26 @@ def avis_new
end

def personnes_impliquees
# sort following_instructeurs (last follower on top) for the API of Agence de l’Eau Loire-Bretagne
@following_instructeurs_emails = dossier.followers_instructeurs.joins(:follows).merge(Follow.order(id: :desc)).map(&:email)
redirect_to suivi_et_decision_instructeur_dossier_path(procedure, dossier), status: :moved_permanently
end

def suivi_et_decision
@following_instructeurs_emails = dossier.followers_instructeurs
.joins(:follows).merge(Follow.order(id: :desc)).map(&:email)
previous_followers = dossier.previous_followers_instructeurs - dossier.followers_instructeurs
@previous_following_instructeurs_emails = previous_followers.map(&:email)
@avis_emails = dossier.experts.map(&:email)
@invites_emails = dossier.invites.map(&:email)
@potential_recipients = dossier.groupe_instructeur.instructeurs.reject { |g| g == current_instructeur }
@manual_assignments = dossier.dossier_assignments.manual.includes(:groupe_instructeur, :previous_groupe_instructeur)
@potential_recipients = dossier.groupe_instructeur.instructeurs
.reject { |g| g == current_instructeur }
@assignments = dossier.dossier_assignments
.includes(:groupe_instructeur, :previous_groupe_instructeur)
.order(:assigned_at)

if dossier.procedure.routing_enabled?
@groupe_instructeur = dossier.groupe_instructeur
@groupes_instructeurs = @groupe_instructeur.other_groupe_instructeurs
end
end

def rendez_vous
Expand Down Expand Up @@ -161,7 +173,7 @@ def send_to_instructeurs
flash.alert = "Instructeur inconnu ou non présent sur la procédure"
end

redirect_to(personnes_impliquees_instructeur_dossier_path(procedure, dossier))
redirect_to(suivi_et_decision_instructeur_dossier_path(procedure, dossier))
end

def follow
Expand Down Expand Up @@ -435,11 +447,7 @@ def restore
end

def reaffectation
@dossier = current_instructeur.dossiers.find(params[:dossier_id]).with_champs

@groupe_instructeur = @dossier.groupe_instructeur

@groupes_instructeurs = @groupe_instructeur.other_groupe_instructeurs
redirect_to suivi_et_decision_instructeur_dossier_path(procedure, dossier), status: :moved_permanently
end

def reaffecter
Expand All @@ -456,7 +464,7 @@ def reaffecter
redirect_to instructeur_procedure_path(procedure)
else
flash.alert = t('instructeurs.dossiers.reaffectation.error')
redirect_to reaffectation_instructeur_dossier_path(dossier.procedure, dossier)
redirect_to suivi_et_decision_instructeur_dossier_path(dossier.procedure, dossier)
end
end

Expand Down
3 changes: 3 additions & 0 deletions app/javascript/components/ComboBox.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -79,13 +79,15 @@ export function ComboBox({
ariaLabelledbyPrefix,
description,
className,
inputId,
inputRef,
isLoading,
isOpen,
placeholder,
items,
...props
}: ComboBoxProps & {
inputId?: string;
inputRef?: RefObject<HTMLInputElement | null>;
isOpen?: boolean;
placeholder?: string;
Expand Down Expand Up @@ -119,6 +121,7 @@ export function ComboBox({
) : null}
<div className="fr-ds-combobox__input" style={{ position: 'relative' }}>
<Input
id={inputId}
className="fr-select fr-autocomplete"
ref={inputRef}
aria-busy={isLoading}
Expand Down
26 changes: 22 additions & 4 deletions app/javascript/components/Select.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@ import {
Autocomplete,
SelectValue,
Button,
Label,
Text,
Popover,
Virtualizer,
ListLayout,
Expand Down Expand Up @@ -42,6 +44,9 @@ type SelectProps<M extends SelectionMode = 'single'> = AriaSelectProps<
items?: Item[];
sections?: Section[];
value: M extends 'single' ? string | null : string[];
label?: string;
description?: string;
triggerId?: string;
labelId?: string;
ariaLabelledbyPrefix?: string;
alwaysShowKey?: string;
Expand All @@ -51,6 +56,9 @@ type AutocompleteFilter = NonNullable<AutocompleteProps<Item>['filter']>;
function Select<M extends SelectionMode = 'single'>({
items,
sections,
label,
description,
triggerId,
labelId,
ariaLabelledbyPrefix,
alwaysShowKey,
Expand All @@ -77,12 +85,22 @@ function Select<M extends SelectionMode = 'single'>({

return (
<AriaSelect {...props}>
{label ? (
<Label className="fr-label">
{label}
{description ? (
<Text slot="description" className="fr-hint-text">
{description}
</Text>
) : null}
</Label>
) : null}
{props.selectionMode == 'single' ? (
<Button className="fr-select">
<Button id={triggerId} className="fr-select">
<SelectValue />
</Button>
) : (
<MultipleSelectValue />
<MultipleSelectValue triggerId={triggerId} />
)}
<Popover
className="react-aria-Popover select-popover"
Expand Down Expand Up @@ -118,13 +136,13 @@ function Select<M extends SelectionMode = 'single'>({
);
}

function MultipleSelectValue() {
function MultipleSelectValue({ triggerId }: { triggerId?: string }) {
const selectButtonRef = useRef<HTMLButtonElement>(null);
return (
<SelectValue<Item>>
{({ selectedItems, state, defaultChildren }) => (
<>
<Button className="fr-select" ref={selectButtonRef}>
<Button id={triggerId} className="fr-select" ref={selectButtonRef}>
<span className="react-aria-SelectValue" data-placeholder>
<Plural
value={selectedItems.length}
Expand Down
3 changes: 3 additions & 0 deletions app/javascript/components/react-aria/props.ts
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ export type Section = { label: string; items: Item[] };
const ComboBoxPropsSchema = s.partial(
s.object({
id: s.string(),
inputId: s.string(),
className: s.string(),
name: s.string(),
label: s.string(),
Expand Down Expand Up @@ -107,8 +108,10 @@ const SelectProps = s.partial(
items: s.union([s.array(Item), ArrayOfStrings, ArrayOfTuples]),
sections: s.array(Section),
id: s.string(),
triggerId: s.string(),
className: s.string(),
name: s.string(),
label: s.string(),
description: s.string(),
isRequired: s.boolean(),
isDisabled: s.boolean(),
Expand Down
13 changes: 0 additions & 13 deletions app/views/instructeurs/dossiers/_envoyer_dossier_block.html.haml

This file was deleted.

Loading
Loading