Skip to content
Open
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
Original file line number Diff line number Diff line change
@@ -1,82 +1,131 @@
<template>

<MessageLayout
<StudioMessageLayout
:header="$tr('forgotPasswordTitle')"
:text="$tr('forgotPasswordPrompt')"
>
<VForm
<form
ref="form"
lazy-validation
novalidate
class="forgot-password-form"
@submit.prevent="submit"
>
<Banner
:text="$tr('forgotPasswordFailed')"
:value="error"
<StudioBanner

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion: Screen-reader users hear nothing when the failure banner appears. It has no live region. Add role="alert", as AccountsMain.vue:36 does. Also replace the Vuetify mb-4 helper with a scoped class (.banner { margin-bottom: 16px } in RequestNewActivationLink.vue).

v-if="error"
error
class="mb-4"
data-testid="error-banner"
/>
<EmailField
>
{{ $tr('forgotPasswordFailed') }}
</StudioBanner>

<StudioEmailField

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

blocking: accounts/pages/__tests__/forgotPassword.spec.js fails. It queries getByLabelText('Email'), but the new field's label is "Email address". Reproduced locally: 1 failed, 4 passed. The AC asks for the suite to be meaningfully updated.

  • Pass :label to keep "Email" (as AccountsMain.vue does), or update the query.
  • Add VTL cases: error shown for empty and invalid input on submit, no request sent.

v-model="email"
autofocus
class="email-field w-100"
:error-messages="emailErrors"
@blur="showEmailError"

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion: The email error hides inconsistently. A mouse click hides it, but tabbing into the field does not. Every keystroke also hides it. RequestNewActivationLink.vue:23 shows the error from errors.email alone; AccountsMain.vue:62 uses a touched flag. Replace emailValidationVisible and its three handlers with one of those patterns. Also use :errorMessages (camelCase), like every other call site.

@input="hideEmailError"
@click.native="hideEmailError"
/>

<KButton
primary
class="w-100"
:text="$tr('submitButton')"
type="submit"
/>
</VForm>
</MessageLayout>
</form>
</StudioMessageLayout>

</template>


<script>

import { mapActions } from 'vuex';
import MessageLayout from '../../components/MessageLayout';
import EmailField from 'shared/views/form/EmailField';
import Banner from 'shared/views/Banner';
import StudioMessageLayout from '../../components/StudioMessageLayout';
import StudioEmailField from '../../components/form/StudioEmailField';
import StudioBanner from '../../../shared/views/StudioBanner';

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nitpick: Use the aliases shared/views/StudioBanner and shared/mixins, as sibling pages do. ref="form" (line 8) is unused now; remove it.

import { generateFormMixin } from '../../../shared/mixins.js';

const formFields = {
email: {
required: true,
validator: value => Boolean(value && /.+@.+\..+/.test(value)),
},
};

export default {
name: 'ForgotPassword',

mixins: [generateFormMixin(formFields)],

components: {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

blocking: Linting CI fails: The "components" property should be above the "mixins" property on line 62 vue/order-in-components. Move mixins below components, as RequestNewActivationLink.vue does.

MessageLayout,
EmailField,
Banner,
StudioMessageLayout,
StudioEmailField,
StudioBanner,
},

data() {
return {
email: '',
error: false,
emailValidationVisible: false,
};
},

computed: {
emailErrors() {
if (!this.emailValidationVisible || !this.errors.email) {
return [];
}

return [this.$tr('validEmailMessage')];

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion: An empty email now shows "Please enter a valid email" instead of "This field is required". That breaks the "no functional differences" AC. Handle both cases as emailErrorText does in RequestNewActivationLink.vue:66-72.

},
},

methods: {
...mapActions('account', ['sendPasswordResetLink']),

hideEmailError() {
this.emailValidationVisible = false;
},

showEmailError() {
this.emailValidationVisible = true;
},

submit() {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

praise: Validation and the payload both use the same trimmed email. QA confirmed a padded email posts as a@a.com.

this.error = false;
if (this.$refs.form.validate()) {
this.sendPasswordResetLink(this.email)
.then(() => {
this.$router
.push({
name: 'PasswordInstructionsSent',
})
.catch(() => {});
})
.catch(() => {
this.error = true;
});

const formData = this.clean();

if (!this.validate(formData)) {
this.emailValidationVisible = true;
return;
}

this.sendPasswordResetLink(formData.email)
.then(() => {
this.$router
.push({
name: 'PasswordInstructionsSent',
})
.catch(() => {});
})
.catch(() => {
this.error = true;
});
},
},

$trs: {
forgotPasswordTitle: 'Reset your password',
forgotPasswordPrompt:
'Please enter your email address to receive instructions for resetting your password',
submitButton: 'Submit',
forgotPasswordFailed: 'Failed to send a password reset link. Please try again.',
validEmailMessage: 'Please enter a valid email',

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion: On /ar/, the error and the field label now render in English. The legacy EmailField.validEmailMessage had an Arabic translation. The new string keys don't. Reuse the existing translated strings for the error and label.

},
};

Expand All @@ -85,8 +134,19 @@

<style lang="scss" scoped>

.forgot-password-form {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion: The validation message and banner text are centred, while the label and input are left-aligned (.reviews/qa-s2-invalid.png). The form inherits text-align: center from StudioMessageLayout. Add text-align: left; here; RTLCSS flips it.

width: 400px;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

blocking: The form is cut off at 320px and 360px widths. The form, field and Submit stay 400px wide. LTR loses the right edge; /ar/ loses the left edge. This fails WCAG 1.4.10 Reflow.

  • Cause: StudioMessageLayout's .message-slot-container shrinks to its content, so max-width: 100% here resolves against 400px.
  • Fix: set .message-slot-container { width: 100%; } (QA: 328px form at 360px, still 400px on desktop), or drop the fixed width here.
  • Screenshots: .reviews/qa-s6-360.png, .reviews/qa-s6-rtl-360.png.

max-width: 100%;
margin: 0 auto;
}

.email-field {
margin-bottom: 24px;
}

.w-100 {
width: 100%;
display: block;
width: 100% !important;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

suggestion: This override also forces display: block and !important onto the KButton. AccountsMain.vue:63 and Create.vue:70 pass :appearanceOverrides="{ maxWidth: '100%' }" to StudioEmailField instead. Use that and restore plain width: 100%.

}

</style>
Loading