Skip to content

Commit ac02370

Browse files
[FEATURE] Afficher la bonne réception de demande de réinitialisation de mot de passe (PIX-14112)
#10402
2 parents 012fa0a + 30c98b9 commit ac02370

File tree

8 files changed

+186
-61
lines changed

8 files changed

+186
-61
lines changed

mon-pix/app/components/authentication/password-reset-demand-form.gjs

+80-52
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@ export default class PasswordResetDemandForm extends Component {
2222
);
2323
@tracked emailInputvalidationStatus;
2424
@tracked emailInputvalidationErrorMessage;
25+
@tracked isPasswordResetDemandReceived = false;
2526

2627
email;
2728

@@ -55,11 +56,11 @@ export default class PasswordResetDemandForm extends Component {
5556
method: 'POST',
5657
body: JSON.stringify({ email }),
5758
});
58-
if (response.status == 404) {
59-
this.errorMessage = this.intl.t('components.authentication.password-reset-demand-form.404-message');
60-
} else if (!response.ok) {
59+
if (!response.ok && response.status != 404) {
6160
throw new Error(`Response status: ${response.status}`);
6261
}
62+
63+
this.isPasswordResetDemandReceived = true;
6364
} catch (error) {
6465
this.errorMessage = this.intl.t('common.api-error-messages.internal-server-error');
6566
} finally {
@@ -68,55 +69,82 @@ export default class PasswordResetDemandForm extends Component {
6869
}
6970

7071
<template>
71-
<form {{on "submit" this.handlePasswordResetDemand}} class="authentication-password-reset-demand-form">
72-
<p class="authentication-password-reset-demand-form__rule">
73-
{{t "components.authentication.password-reset-demand-form.rule"}}
74-
</p>
72+
{{#if this.isPasswordResetDemandReceived}}
73+
<PasswordResetDemandReceivedInfo />
74+
{{else}}
75+
<form {{on "submit" this.handlePasswordResetDemand}} class="authentication-password-reset-demand-form">
76+
<p class="authentication-password-reset-demand-form__rule">
77+
{{t "components.authentication.password-reset-demand-form.rule"}}
78+
</p>
7579

76-
{{#if this.errorMessage}}
77-
<PixMessage
78-
@type="error"
79-
@withIcon={{true}}
80-
class="authentication-password-reset-demand-form__error"
81-
role="alert"
82-
>
83-
{{this.errorMessage}}
84-
</PixMessage>
85-
{{/if}}
86-
<div class="authentication-password-reset-demand-form__input-block">
87-
<PixInput
88-
@value={{this.email}}
89-
type="email"
90-
{{on "change" this.handleEmailChange}}
91-
@validationStatus={{this.emailInputvalidationStatus}}
92-
@errorMessage={{this.emailInputvalidationErrorMessage}}
93-
placeholder={{this.emailInputPlaceholder}}
94-
required={{true}}
95-
>
96-
<:label>{{t "components.authentication.password-reset-demand-form.fields.email.label"}}</:label>
97-
</PixInput>
98-
</div>
99-
<div>
100-
<PixButton
101-
@type="submit"
102-
@size="large"
103-
@isLoading={{this.isLoading}}
104-
class="authentication-password-reset-demand-form__button"
105-
>
106-
{{t "components.authentication.password-reset-demand-form.actions.receive-reset-button"}}
107-
</PixButton>
108-
</div>
109-
<p class="authentication-password-reset-demand-form__help">
110-
{{t "components.authentication.password-reset-demand-form.no-email-question"}}
111-
<PixButtonLink
112-
@variant="tertiary"
113-
@href="{{t 'components.authentication.password-reset-demand-form.contact-us-link.link-url'}}"
114-
target="_blank"
115-
class="authentication-password-reset-demand-form__help-contact-us-link"
116-
>
117-
{{t "components.authentication.password-reset-demand-form.contact-us-link.link-text"}}
118-
</PixButtonLink>
119-
</p>
120-
</form>
80+
{{#if this.errorMessage}}
81+
<PixMessage
82+
@type="error"
83+
@withIcon={{true}}
84+
class="authentication-password-reset-demand-form__error"
85+
role="alert"
86+
>
87+
{{this.errorMessage}}
88+
</PixMessage>
89+
{{/if}}
90+
<div class="authentication-password-reset-demand-form__input-block">
91+
<PixInput
92+
@value={{this.email}}
93+
type="email"
94+
{{on "change" this.handleEmailChange}}
95+
@validationStatus={{this.emailInputvalidationStatus}}
96+
@errorMessage={{this.emailInputvalidationErrorMessage}}
97+
placeholder={{this.emailInputPlaceholder}}
98+
required={{true}}
99+
>
100+
<:label>{{t "components.authentication.password-reset-demand-form.fields.email.label"}}</:label>
101+
</PixInput>
102+
</div>
103+
<div>
104+
<PixButton
105+
@type="submit"
106+
@size="large"
107+
@isLoading={{this.isLoading}}
108+
class="authentication-password-reset-demand-form__button"
109+
>
110+
{{t "components.authentication.password-reset-demand-form.actions.receive-reset-button"}}
111+
</PixButton>
112+
</div>
113+
<p class="authentication-password-reset-demand-form__help">
114+
{{t "components.authentication.password-reset-demand-form.no-email-question"}}
115+
<PixButtonLink
116+
@variant="tertiary"
117+
@href="{{t 'components.authentication.password-reset-demand-form.contact-us-link.link-url'}}"
118+
target="_blank"
119+
class="authentication-password-reset-demand-form__help-contact-us-link"
120+
>
121+
{{t "components.authentication.password-reset-demand-form.contact-us-link.link-text"}}
122+
</PixButtonLink>
123+
</p>
124+
</form>
125+
{{/if}}
121126
</template>
122127
}
128+
129+
const PasswordResetDemandReceivedInfo = <template>
130+
<div class="authentication-password-reset-demand-received-info">
131+
<img src="/images/mail.svg" alt="" />
132+
<h2 class="authentication-password-reset-demand-received-info__heading">
133+
{{t "components.authentication.password-reset-demand-received-info.heading"}}
134+
</h2>
135+
<p class="authentication-password-reset-demand-received-info__message">
136+
{{t "components.authentication.password-reset-demand-received-info.message"}}
137+
</p>
138+
<p class="authentication-password-reset-demand-received-info__help">
139+
{{t "components.authentication.password-reset-demand-received-info.no-email-received-question"}}
140+
<PixButtonLink
141+
@variant="tertiary"
142+
@route="password-reset-demand"
143+
target="_blank"
144+
class="authentication-password-reset-demand-form__help-contact-us-link"
145+
>
146+
{{t "components.authentication.password-reset-demand-received-info.try-again"}}
147+
</PixButtonLink>
148+
</p>
149+
</div>
150+
</template>;

mon-pix/app/components/authentication/password-reset-demand.scss

+27
Original file line numberDiff line numberDiff line change
@@ -38,4 +38,31 @@
3838
display: inline;
3939
padding: 0;
4040
}
41+
}
42+
43+
.authentication-password-reset-demand-received-info {
44+
margin-top: var(--pix-spacing-6x);
45+
padding: var(--pix-spacing-6x);
46+
color: var(--pix-neutral-900);
47+
text-align: center;
48+
background-color: var(--pix-primary-10);
49+
border-radius: var(--pix-spacing-4x);
50+
51+
&__heading {
52+
@extend %pix-title-xs;
53+
54+
margin-top: var(--pix-spacing-8x);
55+
}
56+
57+
&__message {
58+
@extend %pix-body-m;
59+
60+
margin-top: var(--pix-spacing-4x);
61+
}
62+
63+
&__help {
64+
@extend %pix-body-m;
65+
66+
margin-top: var(--pix-spacing-4x);
67+
}
4168
}

mon-pix/public/images/mail.svg

+15
Loading

mon-pix/tests/integration/components/authentication/password-reset-demand-form-test.gjs

+40-5
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,20 @@ module('Integration | Component | Authentication | password-reset-demand-form',
2222
assert.strictEqual(link.getAttribute('href'), 'https://pix.fr/support');
2323
});
2424

25+
test('it doesn’t display a "password reset demand received" info', async function (assert) {
26+
// given
27+
const screen = await render(<template><PasswordResetDemandForm /></template>);
28+
29+
// then
30+
assert
31+
.dom(
32+
screen.queryByRole('heading', {
33+
name: t('components.authentication.password-reset-demand-received-info.heading'),
34+
}),
35+
)
36+
.doesNotExist();
37+
});
38+
2539
module('email input validation', function () {
2640
module('when the email input is valid', function () {
2741
test('it doesn’t display any error message', async function (assert) {
@@ -68,7 +82,7 @@ module('Integration | Component | Authentication | password-reset-demand-form',
6882
});
6983

7084
module('when the password-reset-demand is successful', function () {
71-
test('it doesn’t display any error message', async function (assert) {
85+
test('it displays a "password reset demand received" info (without any error message)', async function (assert) {
7286
// given
7387
window.fetch.resolves(
7488
fetchMock({
@@ -89,11 +103,26 @@ module('Integration | Component | Authentication | password-reset-demand-form',
89103

90104
// then
91105
assert.dom(screen.queryByRole('alert')).doesNotExist();
106+
107+
assert
108+
.dom(
109+
screen.queryByRole('heading', {
110+
name: t('components.authentication.password-reset-demand-received-info.heading'),
111+
}),
112+
)
113+
.exists();
114+
115+
const tryAgainLink = await screen.queryByRole('link', {
116+
name: t('components.authentication.password-reset-demand-received-info.try-again'),
117+
});
118+
assert.dom(tryAgainLink).exists();
119+
assert.strictEqual(tryAgainLink.getAttribute('href'), '/mot-de-passe-oublie');
92120
});
93121
});
94122

123+
// TODO: This test module will need to be removed when the API doesn't leak anymore that an account doesn't exist with a "404 Not Found".
95124
module('when there is no corresponding user account', function () {
96-
test('it displays an "account not found" error message', async function (assert) {
125+
test('it displays a "password reset demand received" info (without any error message to avoid email enumeration)', async function (assert) {
97126
// given
98127
window.fetch.resolves(
99128
fetchMock({
@@ -116,9 +145,15 @@ module('Integration | Component | Authentication | password-reset-demand-form',
116145
);
117146

118147
// then
119-
// The following doesn’t work because of a PixUi span inside the role element
120-
//assert.dom(screen.queryByRole('alert', { name: t('pages.password-reset-demand.error.message') })).exists();
121-
assert.dom(screen.queryByText(t('components.authentication.password-reset-demand-form.404-message'))).exists();
148+
assert.dom(screen.queryByRole('alert')).doesNotExist();
149+
150+
assert
151+
.dom(
152+
screen.queryByRole('heading', {
153+
name: t('components.authentication.password-reset-demand-received-info.heading'),
154+
}),
155+
)
156+
.exists();
122157
});
123158
});
124159

mon-pix/translations/en.json

+6-1
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,6 @@
153153
"signup-heading": "Other ways to sign up"
154154
},
155155
"password-reset-demand-form": {
156-
"404-message": "The email address entered does not match any Pix account",
157156
"actions": {
158157
"receive-reset-button": "Receive a reset link"
159158
},
@@ -171,6 +170,12 @@
171170
"no-email-question": "No email address?",
172171
"rule": "All fields are required."
173172
},
173+
"password-reset-demand-received-info": {
174+
"heading": "Check your email address",
175+
"message": "If your address is associated with a Pix account, instructions for resetting your password have been sent to you by e-mail.",
176+
"no-email-received-question": "You haven’t received anything?",
177+
"try-again": "Try again with another demand"
178+
},
174179
"password-reset-form": {
175180
"actions": {
176181
"submit": "Reset my password"

mon-pix/translations/es.json

+6-1
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,6 @@
187187
}
188188
},
189189
"password-reset-demand-form": {
190-
"404-message": "Esta dirección de correo electrónico no corresponde a ninguna cuenta",
191190
"rule": "All fields are required.",
192191
"no-email-question": "No email address?",
193192
"contact-us-link": {
@@ -204,6 +203,12 @@
204203
"actions": {
205204
"receive-reset-button": "Receive a reset link"
206205
}
206+
},
207+
"password-reset-demand-received-info": {
208+
"heading": "Check your email address",
209+
"message": "If your address is associated with a Pix account, instructions for resetting your password have been sent to you by e-mail.",
210+
"no-email-received-question": "You haven’t received anything?",
211+
"try-again": "Try again with another demand"
207212
}
208213
},
209214
"invited": {

mon-pix/translations/fr.json

+6-1
Original file line numberDiff line numberDiff line change
@@ -153,7 +153,6 @@
153153
"signup-heading": "Autres moyens d’inscription"
154154
},
155155
"password-reset-demand-form": {
156-
"404-message": "Cette adresse e-mail ne correspond à aucun compte",
157156
"actions": {
158157
"receive-reset-button": "Recevoir un lien de réinitialisation"
159158
},
@@ -171,6 +170,12 @@
171170
"no-email-question": "Pas d’adresse e-mail renseignée ?",
172171
"rule": "Tous les champs sont obligatoires."
173172
},
173+
"password-reset-demand-received-info": {
174+
"heading": "Vérifiez votre messagerie électronique",
175+
"message": "Si votre adresse est bien associée à un compte Pix, les instructions pour réinitialiser votre mot de passe vous ont été envoyées par e-mail.",
176+
"no-email-received-question": "Vous n’avez pas reçu d’e-mail ?",
177+
"try-again": "Renvoyer l’e-mail de réinitialisation"
178+
},
174179
"password-reset-form": {
175180
"actions": {
176181
"submit": "Je réinitialise mon mot de passe"

mon-pix/translations/nl.json

+6-1
Original file line numberDiff line numberDiff line change
@@ -187,7 +187,6 @@
187187
}
188188
},
189189
"password-reset-demand-form": {
190-
"404-message": "Dit e-mailadres komt niet overeen met een account",
191190
"rule": "All fields are required.",
192191
"no-email-question": "No email address?",
193192
"contact-us-link": {
@@ -204,6 +203,12 @@
204203
"actions": {
205204
"receive-reset-button": "Receive a reset link"
206205
}
206+
},
207+
"password-reset-demand-received-info": {
208+
"heading": "Check your email address",
209+
"message": "If your address is associated with a Pix account, instructions for resetting your password have been sent to you by e-mail.",
210+
"no-email-received-question": "You haven’t received anything?",
211+
"try-again": "Try again with another demand"
207212
}
208213
},
209214
"invited": {

0 commit comments

Comments
 (0)