Skip to content

Commit 26f0d04

Browse files
authored
Merge pull request #12776 from demarche-numerique/refonte-identity
ETQ usager, refonte UX de la page identité
2 parents 46d5b91 + f6e9a81 commit 26f0d04

38 files changed

Lines changed: 438 additions & 253 deletions

app/components/dossiers/individual_form_component.rb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -22,4 +22,8 @@ def identity_locked?
2222
def mandataire_identity_locked?
2323
@dossier.france_connected_with_one_identity?
2424
end
25+
26+
def back_url
27+
helpers.commencer_path(path: @dossier.procedure.path)
28+
end
2529
end

app/components/dossiers/individual_form_component/individual_form_component.en.yml

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,8 +5,9 @@ en:
55
callout_title: Your information will be forwarded to verify your status
66
callout_text: We will request proof of your situation directly from the relevant authorities. If the information is available, you will not need to provide any supporting documents.
77
for_tiers:
8-
callout_text: "You are acting as a proxy for a principal, either professionally (such as accountant, lawyer, civil servant…) or personally (family). Make sure to respect the conditions of"
8+
callout_text: 'You are acting as a proxy for a principal, either professionally (such as accountant, lawyer, civil servant…) or personally (family). Make sure to respect the conditions of'
99
callout_link: Articles 1984 and following of the Civil Code.
1010
callout_link_title: Articles 1984 and following of the Civil Code.
11-
beneficiaire_title: "Identity of the beneficiary"
11+
beneficiaire_title: 'Identity of the beneficiary'
12+
notify_beneficiary: 'Notify the beneficiary by email about their application processing'
1213
identity_locked_by_france_connect: Your identity information was provided by FranceConnect and cannot be modified.

app/components/dossiers/individual_form_component/individual_form_component.fr.yml

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,5 @@ fr:
99
callout_link: Articles 1984 et suivants du Code civil.
1010
callout_link_title: Articles 1984 et suivants du Code civil.
1111
beneficiaire_title: Identité du bénéficiaire
12+
notify_beneficiary: Informer le bénéficiaire par email du traitement de son dossier
1213
identity_locked_by_france_connect: Vos informations d’identité ont été transmises par FranceConnect et ne peuvent pas être modifiées.
Lines changed: 144 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,144 @@
1+
<%= form_for @dossier, url: update_identite_dossier_path(@dossier), html: { id: 'identite-form', class: "form", "data-controller" => "for-tiers" } do |f| %>
2+
<%= f.hidden_field :for_tiers %>
3+
4+
<% if for_tiers? %>
5+
<div class="fr-alert fr-alert--info fr-mb-4w">
6+
<p class="fr-notice__text">
7+
<%= t('.for_tiers.callout_text') %>
8+
9+
<%= link_to(t('.for_tiers.callout_link'),
10+
'https://www.legifrance.gouv.fr/codes/section_lc/LEGITEXT000006070721/LEGISCTA000006136404/#LEGISCTA000006136404',
11+
title: helpers.new_tab_suffix(t('.for_tiers.callout_link_title')),
12+
**helpers.external_link_attributes) %>
13+
</p>
14+
</div>
15+
<div class="border-grey fr-p-3w fr-mb-4w">
16+
<fieldset class="fr-fieldset mandataire-infos fr-mb-0">
17+
<legend class="fr-fieldset__legend fr-fieldset__legend--regular">
18+
<h2 class="fr-h5"><%= t('.for_self.self_title') %></h2>
19+
</legend>
20+
21+
<% if @dossier.france_connected_with_one_identity? %>
22+
<div class="fr-highlight fr-text--sm">
23+
<%= t('.identity_locked_by_france_connect') %>
24+
</div>
25+
<% end %>
26+
27+
<div class="fr-fieldset__element fr-fieldset__element--short-text">
28+
<%= render Dsfr::InputComponent.new(form: f, attribute: :mandataire_first_name, opts: { autocomplete: 'given-name', disabled: mandataire_identity_locked? }) %>
29+
</div>
30+
31+
<div class="fr-fieldset__element fr-fieldset__element--short-text">
32+
<%= render Dsfr::InputComponent.new(form: f, attribute: :mandataire_last_name, opts: { autocomplete: 'family-name', disabled: mandataire_identity_locked? }) %>
33+
</div>
34+
</fieldset>
35+
</div>
36+
<% elsif can_personal_data_be_transmitted? %>
37+
<%= render Dsfr::AlertComponent.new(title: t('.for_self.callout_title'), state: :info, with_prefix: false, extra_class_names: 'fr-mb-2w') do |c| %>
38+
<% c.with_body do %>
39+
<%= t('.for_self.callout_text') %>
40+
<% end %>
41+
<% end %>
42+
<% end %>
43+
44+
<%= f.fields_for :individual, include_id: false do |individual| %>
45+
<div class="border-grey fr-p-3w fr-mb-4w">
46+
<fieldset class="fr-fieldset individual-infos fr-mb-0">
47+
<legend class="fr-fieldset__legend fr-fieldset__legend--regular">
48+
<h2 class="fr-h5">
49+
<% if for_tiers? %>
50+
<%= t('.for_tiers.beneficiaire_title') %>
51+
<% else %>
52+
<%= t('.for_self.self_title') %>
53+
<% end %>
54+
</h2>
55+
</legend>
56+
57+
<% if @dossier.france_connected_with_one_identity? && !for_tiers? %>
58+
<div class="fr-highlight fr-text--sm">
59+
<%= t('.identity_locked_by_france_connect') %>
60+
</div>
61+
<% end %>
62+
63+
<% unless @dossier.procedure.no_gender? %>
64+
<div class="fr-fieldset__element">
65+
<%= render Dsfr::RadioButtonListComponent.new(
66+
form: individual,
67+
target: :gender,
68+
buttons: [
69+
{ label: Individual.human_attribute_name('gender.female'), value: Individual::GENDER_FEMALE, required: true, disabled: identity_locked?, translate: "no" },
70+
{ label: Individual.human_attribute_name('gender.male'), value: Individual::GENDER_MALE, required: true, disabled: identity_locked?, translate: "no" }
71+
],
72+
error: individual.object.errors.full_messages_for(:gender).first,
73+
inline: true
74+
) do %>
75+
<%= t('activerecord.attributes.individual.gender') %>
76+
<%= render EditableChamp::AsteriskMandatoryComponent.new %>
77+
<% end %>
78+
</div>
79+
<% end %>
80+
81+
<div class="fr-fieldset__element fr-fieldset__element--short-text">
82+
<% if for_tiers? %>
83+
<%= render Dsfr::InputComponent.new(form: individual, attribute: :prenom) %>
84+
<% else %>
85+
<%= render Dsfr::InputComponent.new(form: individual, attribute: :prenom, opts: { autocomplete: 'given-name', disabled: identity_locked? }) %>
86+
<% end %>
87+
</div>
88+
89+
<div class="fr-fieldset__element fr-fieldset__element--short-text">
90+
<% if for_tiers? %>
91+
<%= render Dsfr::InputComponent.new(form: individual, attribute: :nom) %>
92+
<% else %>
93+
<%= render Dsfr::InputComponent.new(form: individual, attribute: :nom, opts: { autocomplete: 'family-name', disabled: identity_locked? }) %>
94+
<% end %>
95+
</div>
96+
97+
<% if @dossier.procedure.ask_birthday? %>
98+
<div class="fr-fieldset__element">
99+
<%= render Dsfr::InputComponent.new(form: individual, attribute: :birthdate, input_type: :date_field,
100+
opts: { placeholder: 'Format : AAAA-MM-JJ', max: Date.today.iso8601, min: "1900-01-01", autocomplete: 'bday' }) %>
101+
</div>
102+
<% end %>
103+
104+
<% if for_tiers? %>
105+
<div class="fr-fieldset__element">
106+
<div class="fr-checkbox-group fr-mt-2w <%= 'fr-checkbox-group--error' if individual.object.errors.include?(:notification_method) %>">
107+
<%= individual.check_box :notification_method, {
108+
id: "notification_method_checkbox",
109+
checked: email_notifications?(individual),
110+
"data-action" => "for-tiers#toggleEmailInput",
111+
"data-for-tiers-target" => "notificationMethodCheckbox",
112+
"aria-describedby" => individual.object.errors.include?(:notification_method) ? "individual_notification_method-error" : nil
113+
}, 'email', 'no_notification' %>
114+
115+
<label class="fr-label" for="notification_method_checkbox">
116+
<%= t('.for_tiers.notify_beneficiary') %>
117+
</label>
118+
119+
<% if individual.object.errors.include?(:notification_method) %>
120+
<p
121+
class="fr-error-text"
122+
id="individual_notification_method-error"
123+
>
124+
<%= individual.object.errors.full_messages_for(:notification_method).first %>
125+
</p>
126+
<% end %>
127+
</div>
128+
</div>
129+
<div
130+
class="fr-fieldset__element fr-fieldset__element--short-text <%= 'hidden' unless email_notifications?(individual) %>"
131+
data-for-tiers-target="emailContainer"
132+
>
133+
<%= render Dsfr::InputComponent.new(form: individual, attribute: :email, input_type: :email_field, opts: { "data-for-tiers-target" => "emailInput" }) %>
134+
</div>
135+
<% end %>
136+
</fieldset>
137+
</div>
138+
<% end %>
139+
140+
<div class="fr-btns-group fr-btns-group--inline">
141+
<%= link_to t('views.users.dossiers.identite.back'), back_url, class: "fr-btn fr-btn--secondary" %>
142+
<%= f.submit t('views.users.dossiers.identite.continue'), class: "fr-btn", "data-email-input-target": "next" %>
143+
</div>
144+
<% end %>

app/components/dossiers/individual_form_component/individual_form_component.html.haml

Lines changed: 0 additions & 101 deletions
This file was deleted.

app/components/dsfr/input_component.rb

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,7 @@ def input_group_opts
3838
class: class_names({
3939
'fr-input-group': true,
4040
'fr-password': password?,
41+
'fr-input-group--disabled': @opts[:disabled],
4142
}.merge(input_group_error_class_names)),
4243
}
4344
if email?

app/components/dsfr/radio_button_list_component.rb

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,10 @@ def error?
2020
@error.present?
2121
end
2222

23+
def disabled?
24+
@buttons.all? { _1[:disabled] }
25+
end
26+
2327
def each_button
2428
@buttons.each.with_index do |button, index|
2529
yield(*button.values_at(:label, :value, :hint, :tooltip), **button.merge!(index:).except(:label, :value, :hint, :tooltip))

app/components/dsfr/radio_button_list_component/radio_button_list_component.html.erb

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,12 @@
11
<fieldset
22
class="<%= class_names("fr-fieldset": true, "fr-fieldset--error": error?) %>"
33
aria-labelledby="<%= legend_id %> <%= messages_id %>"
4-
<%= error? ? 'role="group"' : "" %>
4+
<% if disabled? %>
5+
disabled="disabled"
6+
<% end %>
7+
<% if error? %>
8+
role="group"
9+
<% end %>
510
>
611
<legend
712
class="<%= class_names("fr-fieldset__legend" => true, "fr-fieldset__legend--regular" => @regular_legend) %>"

app/components/instructeurs/activate_account_form_component/activate_account_form_component.html.haml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212
%p= t('asterisk_html', scope: [:utils])
1313

1414
.fr-fieldset__element
15-
= render Dsfr::InputComponent.new(form: f, attribute: :email, input_type: :email_field, opts: { disabled: :disabled, class: 'fr-input-group--disabled' })
15+
= render Dsfr::InputComponent.new(form: f, attribute: :email, input_type: :email_field, opts: { disabled: :disabled })
1616

1717
.fr-fieldset__element
1818
= render Dsfr::InputComponent.new(form: f, attribute: :password, input_type: :password_field,

app/javascript/controllers/for_tiers_controller.ts

Lines changed: 11 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12,14 +12,22 @@ function onHiddenDisableInputs(element: HTMLInputElement) {
1212
}
1313

1414
export class ForTiersController extends ApplicationController {
15-
static targets = ['emailContainer', 'emailInput', 'notificationMethod'];
15+
static targets = [
16+
'emailContainer',
17+
'emailInput',
18+
'notificationMethodCheckbox'
19+
];
1620

17-
declare notificationMethodTargets: NodeListOf<HTMLInputElement>;
21+
declare notificationMethodCheckboxTarget: HTMLInputElement;
1822
declare emailContainerTarget: HTMLElement;
1923
declare emailInputTarget: HTMLInputElement;
2024

25+
connect() {
26+
this.toggleEmailInput();
27+
}
28+
2129
toggleEmailInput() {
22-
const isEmailSelected = this.isEmailSelected();
30+
const isEmailSelected = this.notificationMethodCheckboxTarget.checked;
2331

2432
toggle(this.emailContainerTarget, isEmailSelected);
2533

@@ -29,10 +37,4 @@ export class ForTiersController extends ApplicationController {
2937
onHiddenDisableInputs(this.emailInputTarget);
3038
}
3139
}
32-
33-
isEmailSelected() {
34-
return Array.from(this.notificationMethodTargets).some(
35-
(radio) => radio.value === 'email' && radio.checked
36-
);
37-
}
3840
}

0 commit comments

Comments
 (0)