feat(settings): Enable collapsing/expanding reset password warning
Because: * We want to collapse the warning message on mobile by default to preserve real estate This commit: * Move the warning into a separate component * Convert to use the details/summary elements * Styling tweaks * Copy updates to match latest design for complete reset password * Remove unused old version of WarningMessage Closes #FXA-10459
|
@ -83,7 +83,7 @@ export class ResetPasswordPage extends BaseLayout {
|
|||
}
|
||||
|
||||
get reenterPasswordTextbox() {
|
||||
return this.page.getByRole('textbox', { name: 'Re-enter password' });
|
||||
return this.page.getByRole('textbox', { name: 'Confirm password' });
|
||||
}
|
||||
|
||||
get resetPasswordButton() {
|
||||
|
@ -115,14 +115,12 @@ export class ResetPasswordPage extends BaseLayout {
|
|||
}
|
||||
|
||||
get dataLossWarning() {
|
||||
return this.page.getByText(
|
||||
'Resetting your password may delete your encrypted browser data.'
|
||||
);
|
||||
return this.page.getByText('Your browser data may not be recovered');
|
||||
}
|
||||
|
||||
get resetPasswordWithRecoveryKey() {
|
||||
return this.page.getByRole('link', {
|
||||
name: 'Reset your password with your recovery key.',
|
||||
name: 'Reset your password and keep your data',
|
||||
});
|
||||
}
|
||||
|
||||
|
|
|
@ -9,8 +9,8 @@ form-password-with-inline-criteria-signup-submit-button = Create account
|
|||
form-password-with-inline-criteria-reset-new-password =
|
||||
.label = New password
|
||||
form-password-with-inline-criteria-confirm-password =
|
||||
.label = Re-enter password
|
||||
form-password-with-inline-criteria-reset-submit-button-2 = Create new password
|
||||
.label = Confirm password
|
||||
form-password-with-inline-criteria-reset-submit-button = Create new password
|
||||
|
||||
form-password-with-inline-criteria-match-error = Passwords do not match
|
||||
form-password-with-inline-criteria-sr-too-short-message = Password must contain at least 8 characters.
|
||||
|
|
|
@ -27,7 +27,7 @@ describe('FormPasswordWithInlineCriteria component', () => {
|
|||
await waitFor(() => {
|
||||
screen.getByLabelText('New password');
|
||||
});
|
||||
screen.getByLabelText('Re-enter password');
|
||||
screen.getByLabelText('Confirm password');
|
||||
screen.getByRole('button', { name: 'Create new password' });
|
||||
});
|
||||
|
||||
|
|
|
@ -54,9 +54,9 @@ const getTemplateValues = (passwordFormType: PasswordFormType) => {
|
|||
templateValues.passwordLabel = 'New password';
|
||||
templateValues.confirmPasswordFtlId =
|
||||
'form-password-with-inline-criteria-confirm-password';
|
||||
templateValues.confirmPasswordLabel = 'Re-enter password';
|
||||
templateValues.confirmPasswordLabel = 'Confirm password';
|
||||
templateValues.buttonFtlId =
|
||||
'form-password-with-inline-criteria-reset-submit-button-2';
|
||||
'form-password-with-inline-criteria-reset-submit-button';
|
||||
templateValues.buttonText = 'Create new password';
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -34,7 +34,7 @@ export const PasswordStrengthInline = ({
|
|||
}: PasswordStrengthInlineProps) => {
|
||||
return (
|
||||
<div
|
||||
className="leading-5 text-sm"
|
||||
className="text-sm mb-2"
|
||||
id="password-strength-inline"
|
||||
aria-live="polite"
|
||||
>
|
||||
|
@ -42,23 +42,17 @@ export const PasswordStrengthInline = ({
|
|||
Pick a strong password you haven’t used on other sites. Ensure it meets
|
||||
the security requirements:
|
||||
</p>
|
||||
<ul className="mt-2 mb-2">
|
||||
<li data-testid="password-min-char-req" className="flex ">
|
||||
<ul className="mt-2 mb-2 text-grey-400">
|
||||
<li data-testid="password-min-char-req" className="flex -mb-1">
|
||||
<span className="w-7 h-7 text-center">
|
||||
{isPasswordEmpty && '•'}
|
||||
{!isPasswordEmpty && <ValidationIcon hasError={isTooShort} />}
|
||||
</span>
|
||||
<FtlMsg id="password-strength-inline-min-length">
|
||||
<span
|
||||
className={`ps-2 ${
|
||||
!isPasswordEmpty && isTooShort ? 'text-red-700' : ''
|
||||
}`}
|
||||
>
|
||||
At least 8 characters
|
||||
</span>
|
||||
<span className="ps-2">At least 8 characters</span>
|
||||
</FtlMsg>
|
||||
</li>
|
||||
<li data-testid="password-not-email-req" className="flex ">
|
||||
<li data-testid="password-not-email-req" className="flex -mb-1">
|
||||
<span className="w-7 h-7 text-center">
|
||||
{isPasswordEmpty && '•'}
|
||||
{!isPasswordEmpty && (
|
||||
|
@ -66,34 +60,20 @@ export const PasswordStrengthInline = ({
|
|||
)}
|
||||
</span>
|
||||
<FtlMsg id="password-strength-inline-not-email">
|
||||
<span
|
||||
className={`ps-2 ${
|
||||
!isPasswordEmpty && !isTooShort && isSameAsEmail
|
||||
? 'text-red-700'
|
||||
: ''
|
||||
}`}
|
||||
>
|
||||
Not your email address
|
||||
</span>
|
||||
<span className="ps-2">Not your email address</span>
|
||||
</FtlMsg>
|
||||
</li>
|
||||
<li data-testid="password-not-common-req" className="flex ">
|
||||
<li data-testid="password-not-common-req" className="flex -mb-1">
|
||||
<span className="w-7 h-7 text-center">
|
||||
{isPasswordEmpty && '•'}
|
||||
{!isPasswordEmpty && <ValidationIcon hasError={isCommon} />}
|
||||
</span>
|
||||
<FtlMsg id="password-strength-inline-not-common">
|
||||
<span
|
||||
className={`ps-2 ${
|
||||
!isPasswordEmpty && isCommon ? 'text-red-700' : ''
|
||||
}`}
|
||||
>
|
||||
Not a commonly used password
|
||||
</span>
|
||||
<span className="ps-2">Not a commonly used password</span>
|
||||
</FtlMsg>
|
||||
</li>
|
||||
{isUnconfirmed !== undefined && (
|
||||
<li data-testid="passwords-match" className="flex ">
|
||||
<li data-testid="passwords-match" className="flex">
|
||||
<span className="w-7 h-7 text-center">
|
||||
{(isPasswordEmpty || isConfirmedPasswordEmpty) && '•'}
|
||||
{!(isPasswordEmpty || isConfirmedPasswordEmpty) && (
|
||||
|
@ -101,13 +81,7 @@ export const PasswordStrengthInline = ({
|
|||
)}
|
||||
</span>
|
||||
<FtlMsg id="password-strength-inline-confirmed-must-match">
|
||||
<span
|
||||
className={`ps-2 ${
|
||||
!isPasswordEmpty && !isConfirmedPasswordEmpty && isUnconfirmed
|
||||
? 'text-red-700'
|
||||
: ''
|
||||
}`}
|
||||
>
|
||||
<span className="ps-2">
|
||||
Confirmation matches the new password
|
||||
</span>
|
||||
</FtlMsg>
|
||||
|
|
|
@ -0,0 +1,3 @@
|
|||
<svg width="12" height="7" viewBox="0 0 12 7" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<path d="M6.35201 6.99891L11.818 1.53391C11.8762 1.47594 11.9224 1.40702 11.9539 1.33113C11.9854 1.25524 12.0016 1.17387 12.0015 1.0917C12.0014 1.00954 11.985 0.928201 11.9534 0.852379C11.9217 0.776558 11.8754 0.707747 11.817 0.649909C11.6994 0.533089 11.5403 0.467529 11.3745 0.467529C11.2087 0.467529 11.0497 0.533089 10.932 0.649909L5.99801 5.58491L1.06801 0.650908C0.949644 0.53853 0.79207 0.476823 0.628869 0.47894C0.465668 0.481056 0.309748 0.546828 0.194338 0.662238C0.0789275 0.777648 0.0131553 0.933569 0.011039 1.09677C0.0089227 1.25997 0.0706296 1.41754 0.183008 1.53591L5.64801 6.99991L6.35201 6.99891Z" fill="#15141A"/>
|
||||
</svg>
|
После Ширина: | Высота: | Размер: 734 B |
|
@ -0,0 +1,13 @@
|
|||
## ResetPasswordWarning component
|
||||
## Warning shown to sync users that reset their password without using an account recovery key
|
||||
|
||||
password-reset-warning-icon = Warning
|
||||
password-reset-chevron-expanded = Collapse warning
|
||||
password-reset-chevron-collapsed = Expand warning
|
||||
|
||||
password-reset-data-may-not-be-recovered = Your browser data may not be recovered
|
||||
password-reset-previously-signed-in-device = Have a device where you previously signed in?
|
||||
password-reset-data-may-be-saved-locally = Your browser data may be locally saved on that device. Sign in there with your new password to restore and sync.
|
||||
password-reset-no-old-device = Have a new device but don’t have your old one?
|
||||
password-reset-encrypted-data-cannot-be-recovered = We’re sorry, but your encrypted browser data on Firefox servers can’t be recovered. However, you can still access your local data on any device where you have previously signed in.
|
||||
password-reset-learn-about-restoring-account-data = Learn more about restoring account data
|
|
@ -1,6 +1,6 @@
|
|||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g id="16 - Non-Sync / device / non-synce device-16">
|
||||
<path id="Subtract" fill-rule="evenodd" clip-rule="evenodd" d="M2.1406 3.26192C2.04987 3.49028 2 3.73932 2 4V10C2 11.1046 2.89543 12 4 12H7.25V13.25H4.5C4.08579 13.25 3.75 13.5858 3.75 14C3.75 14.4142 4.08579 14.75 4.5 14.75H8H11.5C11.9142 14.75 12.25 14.4142 12.25 14C12.25 13.5858 11.9142 13.25 11.5 13.25H8.75V12H10.8787L9.37868 10.5H4C3.72386 10.5 3.5 10.2761 3.5 10V4.62132L2.1406 3.26192ZM12.5 9.37868V4C12.5 3.72386 12.2761 3.5 12 3.5H6.62132L5.12132 2H12C13.1046 2 14 2.89543 14 4V10C14 10.2607 13.9501 10.5097 13.8594 10.7381L12.5 9.37868Z" fill="#15141A"/>
|
||||
<path id="Subtract" fill-rule="evenodd" clip-rule="evenodd" d="M2.1406 3.26192C2.04987 3.49028 2 3.73932 2 4V10C2 11.1046 2.89543 12 4 12H7.25V13.25H4.5C4.08579 13.25 3.75 13.5858 3.75 14C3.75 14.4142 4.08579 14.75 4.5 14.75H8H11.5C11.9142 14.75 12.25 14.4142 12.25 14C12.25 13.5858 11.9142 13.25 11.5 13.25H8.75V12H10.8787L9.37868 10.5H4C3.72386 10.5 3.5 10.2761 3.5 10V4.62132L2.1406 3.26192ZM12.5 9.37868V4C12.5 3.72386 12.2761 3.5 12 3.5H6.62132L5.12132 2H12C13.1046 2 14 2.89543 14 4V10C14 10.2607 13.9501 10.5097 13.8594 10.7381L12.5 9.37868Z" fill="currentColor"/>
|
||||
<path id="Vector 470" d="M3 2L13 12" stroke="#15141A" stroke-width="1.5" stroke-linecap="round"/>
|
||||
</g>
|
||||
</svg>
|
До Ширина: | Высота: | Размер: 827 B После Ширина: | Высота: | Размер: 832 B |
|
@ -1,6 +1,6 @@
|
|||
<svg width="16" height="16" viewBox="0 0 16 16" fill="none" xmlns="http://www.w3.org/2000/svg">
|
||||
<g id=" 16 - Sync / device / synce device-16">
|
||||
<path id="Vector 474" d="M5.5 6.5L7.5 8.5L11 5" stroke="#15141A" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="Union" fill-rule="evenodd" clip-rule="evenodd" d="M4 3.5H12C12.2761 3.5 12.5 3.72386 12.5 4V10C12.5 10.2761 12.2761 10.5 12 10.5H4C3.72386 10.5 3.5 10.2761 3.5 10V4C3.5 3.72386 3.72386 3.5 4 3.5ZM2 4C2 2.89543 2.89543 2 4 2H12C13.1046 2 14 2.89543 14 4V10C14 11.1046 13.1046 12 12 12H8.75V13.25H11.5C11.9142 13.25 12.25 13.5858 12.25 14C12.25 14.4142 11.9142 14.75 11.5 14.75H8H4.5C4.08579 14.75 3.75 14.4142 3.75 14C3.75 13.5858 4.08579 13.25 4.5 13.25H7.25V12H4C2.89543 12 2 11.1046 2 10V4Z" fill="#15141A"/>
|
||||
<path id="Vector 474" d="M5.5 6.5L7.5 8.5L11 5" stroke="currentColor" stroke-width="1.5" stroke-linecap="round" stroke-linejoin="round"/>
|
||||
<path id="Union" fill-rule="evenodd" clip-rule="evenodd" d="M4 3.5H12C12.2761 3.5 12.5 3.72386 12.5 4V10C12.5 10.2761 12.2761 10.5 12 10.5H4C3.72386 10.5 3.5 10.2761 3.5 10V4C3.5 3.72386 3.72386 3.5 4 3.5ZM2 4C2 2.89543 2.89543 2 4 2H12C13.1046 2 14 2.89543 14 4V10C14 11.1046 13.1046 12 12 12H8.75V13.25H11.5C11.9142 13.25 12.25 13.5858 12.25 14C12.25 14.4142 11.9142 14.75 11.5 14.75H8H4.5C4.08579 14.75 3.75 14.4142 3.75 14C3.75 13.5858 4.08579 13.25 4.5 13.25H7.25V12H4C2.89543 12 2 11.1046 2 10V4Z" fill="currentColor"/>
|
||||
</g>
|
||||
</svg>
|
До Ширина: | Высота: | Размер: 809 B После Ширина: | Высота: | Размер: 819 B |
До Ширина: | Высота: | Размер: 893 B После Ширина: | Высота: | Размер: 893 B |
|
@ -3,29 +3,19 @@
|
|||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
import React from 'react';
|
||||
import WarningMessage from '.';
|
||||
import AppLayout from '../AppLayout';
|
||||
import { Meta } from '@storybook/react';
|
||||
import {
|
||||
MOCK_WARNING_MESSAGE_FTL_ID,
|
||||
MOCK_WARNING_MESSAGE,
|
||||
MOCK_WARNING_TYPE,
|
||||
} from './mocks';
|
||||
import { withLocalization } from 'fxa-react/lib/storybooks';
|
||||
import ResetPasswordWarning from '.';
|
||||
import AppLayout from '../AppLayout';
|
||||
|
||||
export default {
|
||||
title: 'Components/WarningMessage',
|
||||
component: WarningMessage,
|
||||
title: 'Components/ResetPasswordWarning',
|
||||
component: ResetPasswordWarning,
|
||||
decorators: [withLocalization],
|
||||
} as Meta;
|
||||
|
||||
export const Default = () => (
|
||||
<AppLayout>
|
||||
<WarningMessage
|
||||
warningMessageFtlId={MOCK_WARNING_MESSAGE_FTL_ID}
|
||||
warningType={MOCK_WARNING_TYPE}
|
||||
>
|
||||
{MOCK_WARNING_MESSAGE}
|
||||
</WarningMessage>
|
||||
<ResetPasswordWarning />
|
||||
</AppLayout>
|
||||
);
|
|
@ -0,0 +1,110 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
import { renderWithLocalizationProvider } from 'fxa-react/lib/test-utils/localizationProvider';
|
||||
import { screen, waitFor } from '@testing-library/react';
|
||||
import ResetPasswordWarning from '.';
|
||||
import userEvent from '@testing-library/user-event';
|
||||
|
||||
describe('ResetPasswordWarning component', () => {
|
||||
it('renders as expected', async () => {
|
||||
renderWithLocalizationProvider(<ResetPasswordWarning />);
|
||||
|
||||
expect(
|
||||
screen.getByRole('img', {
|
||||
name: 'Warning',
|
||||
})
|
||||
).toBeVisible();
|
||||
|
||||
expect(
|
||||
screen.getByText('Your browser data may not be recovered')
|
||||
).toBeVisible();
|
||||
|
||||
expect(screen.getByRole('img', { name: 'Collapse warning' })).toBeVisible();
|
||||
|
||||
expect(
|
||||
screen.getByText('Have a device where you previously signed in?')
|
||||
).toBeVisible();
|
||||
|
||||
expect(
|
||||
screen.getByText(
|
||||
'Your browser data may be locally saved on that device. Sign in there with your new password to restore and sync.'
|
||||
)
|
||||
).toBeVisible();
|
||||
|
||||
expect(
|
||||
screen.getByText('Have a new device but don’t have your old one?')
|
||||
).toBeVisible();
|
||||
|
||||
expect(
|
||||
screen.getByText(
|
||||
'We’re sorry, but your encrypted browser data on Firefox servers can’t be recovered. However, you can still access your local data on any device where you have previously signed in.'
|
||||
)
|
||||
).toBeVisible();
|
||||
|
||||
expect(
|
||||
screen.getByRole('link', {
|
||||
name: 'Learn more about restoring account data',
|
||||
})
|
||||
).toBeVisible();
|
||||
|
||||
expect(screen.getByRole('link')).toHaveAttribute(
|
||||
'href',
|
||||
'https://support.mozilla.org/kb/how-reset-your-password-without-account-recovery-keys-access-data'
|
||||
);
|
||||
});
|
||||
|
||||
it('renders as expected with mobile width', async () => {
|
||||
global.innerWidth = 375; // Set mobile width
|
||||
global.dispatchEvent(new Event('resize'));
|
||||
|
||||
renderWithLocalizationProvider(<ResetPasswordWarning />);
|
||||
|
||||
expect(
|
||||
screen.getByRole('img', {
|
||||
name: 'Warning',
|
||||
})
|
||||
).toBeVisible();
|
||||
|
||||
expect(
|
||||
screen.getByText('Your browser data may not be recovered')
|
||||
).toBeVisible();
|
||||
|
||||
expect(screen.getByRole('img', { name: 'Expand warning' })).toBeVisible();
|
||||
|
||||
expect(
|
||||
screen.queryByText('Have a device where you previously signed in?')
|
||||
).not.toBeVisible();
|
||||
});
|
||||
|
||||
it('handles click/toggle as expected', async () => {
|
||||
const user = userEvent.setup();
|
||||
global.innerWidth = 375; // Set mobile width
|
||||
global.dispatchEvent(new Event('resize'));
|
||||
|
||||
renderWithLocalizationProvider(<ResetPasswordWarning />);
|
||||
|
||||
user.click(screen.getByRole('img', { name: 'Expand warning' }));
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.getByRole('group')).toHaveAttribute('open');
|
||||
expect(
|
||||
screen.getByRole('img', { name: 'Collapse warning' })
|
||||
).toBeVisible();
|
||||
expect(
|
||||
screen.queryByRole('img', { name: 'Expand warning' })
|
||||
).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
user.click(screen.getByRole('img', { name: 'Collapse warning' }));
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.getByRole('group')).not.toHaveAttribute('open');
|
||||
expect(screen.getByRole('img', { name: 'Expand warning' })).toBeVisible();
|
||||
expect(
|
||||
screen.queryByRole('img', { name: 'Collapse warning' })
|
||||
).not.toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
});
|
|
@ -0,0 +1,103 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
import React, { useState } from 'react';
|
||||
|
||||
import { ReactComponent as WarnIcon } from './icon-warn.svg';
|
||||
import { ReactComponent as IconNonSyncDevice } from './icon-non-sync-device.svg';
|
||||
import { ReactComponent as IconSyncDevice } from './icon-sync-device.svg';
|
||||
import { ReactComponent as Chevron } from './chevron.svg';
|
||||
|
||||
import { FtlMsg } from 'fxa-react/lib/utils';
|
||||
import { useFtlMsgResolver } from '../../models';
|
||||
|
||||
const ResetPasswordWarning = () => {
|
||||
const ftlMsgResolver = useFtlMsgResolver();
|
||||
// component is expanded by default on desktop
|
||||
// and collapsed by default on mobile
|
||||
const defaultOpenState = window.innerWidth > 480;
|
||||
const [expanded, setExpanded] = useState(defaultOpenState);
|
||||
|
||||
return (
|
||||
<details
|
||||
className="p-4 bg-orange-50 rounded-lg text-sm text-start border border-transparent"
|
||||
data-testid="warning-message-container"
|
||||
open={defaultOpenState}
|
||||
onToggle={(e) =>
|
||||
setExpanded((e.currentTarget as HTMLDetailsElement).open)
|
||||
}
|
||||
>
|
||||
{/* Arbitrary varaite [&::-webkit-details-marker]:hidden removes the list arrow on webkit based browsers */}
|
||||
<summary className="flex items-center cursor-pointer list-none [&::-webkit-details-marker]:hidden">
|
||||
<WarnIcon
|
||||
role="img"
|
||||
className="flex-initial me-4"
|
||||
aria-label={ftlMsgResolver.getMsg(
|
||||
'reset-password-warning-icon',
|
||||
'Warning'
|
||||
)}
|
||||
/>
|
||||
<p className="flex-1 font-semibold">
|
||||
<FtlMsg id="password-reset-data-may-not-be-recovered">
|
||||
Your browser data may not be recovered
|
||||
</FtlMsg>
|
||||
</p>
|
||||
<Chevron
|
||||
role="img"
|
||||
className={`ms-2 ${expanded ? '-rotate-180' : ''}`}
|
||||
aria-label={expanded ? 'Collapse warning' : 'Expand warning'}
|
||||
/>
|
||||
</summary>
|
||||
<div className="flex flex-col ps-8 pt-4 pb-2 gap-4">
|
||||
<div className="flex items-start gap-2">
|
||||
<IconSyncDevice
|
||||
role="img"
|
||||
className="flex-initial"
|
||||
aria-hidden={true}
|
||||
/>
|
||||
<div className="flex flex-col flex-1 -mt-1 gap-1">
|
||||
<FtlMsg id="password-reset-previously-signed-in-device">
|
||||
<p className="font-semibold">
|
||||
Have a device where you previously signed in?
|
||||
</p>
|
||||
</FtlMsg>
|
||||
<p className="text-grey-500 text-xs">
|
||||
<FtlMsg id="password-reset-data-may-be-saved-locally">
|
||||
Your browser data may be locally saved on that device. Sign in
|
||||
there with your new password to restore and sync.
|
||||
</FtlMsg>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex items-start gap-2">
|
||||
<IconNonSyncDevice role="img" aria-hidden={true} />
|
||||
<div className="flex flex-col flex-1 -mt-1 gap-1">
|
||||
<FtlMsg id="password-reset-no-old-device">
|
||||
<p className="font-semibold">
|
||||
Have a new device but don’t have your old one?
|
||||
</p>
|
||||
</FtlMsg>
|
||||
<FtlMsg id="password-reset-encrypted-data-cannot-be-recovered">
|
||||
<p className="text-grey-500 text-xs">
|
||||
We’re sorry, but your encrypted browser data on Firefox servers
|
||||
can’t be recovered. However, you can still access your local
|
||||
data on any device where you have previously signed in.
|
||||
</p>
|
||||
</FtlMsg>
|
||||
<FtlMsg id="password-reset-learn-about-restoring-account-data">
|
||||
<a
|
||||
href="https://support.mozilla.org/kb/how-reset-your-password-without-account-recovery-keys-access-data"
|
||||
className="link-blue"
|
||||
>
|
||||
Learn more about restoring account data
|
||||
</a>
|
||||
</FtlMsg>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</details>
|
||||
);
|
||||
};
|
||||
|
||||
export default ResetPasswordWarning;
|
|
@ -1,39 +0,0 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
import React from 'react';
|
||||
import { screen } from '@testing-library/react';
|
||||
import { renderWithLocalizationProvider } from 'fxa-react/lib/test-utils/localizationProvider'; // import { getFtlBundle, testAllL10n } from 'fxa-react/lib/test-utils';
|
||||
// import { FluentBundle } from '@fluent/bundle';
|
||||
|
||||
import WarningMessage from '.';
|
||||
import {
|
||||
MOCK_WARNING_MESSAGE_FTL_ID,
|
||||
MOCK_WARNING_MESSAGE,
|
||||
MOCK_WARNING_TYPE,
|
||||
} from './mocks';
|
||||
|
||||
describe('WarningMessage', () => {
|
||||
// TODO: Enable l10n testing with id passed as prop
|
||||
// let bundle: FluentBundle;
|
||||
// beforeAll(async () => {
|
||||
// bundle = await getFtlBundle('settings');
|
||||
// });
|
||||
|
||||
it('renders as expected', () => {
|
||||
renderWithLocalizationProvider(
|
||||
<WarningMessage
|
||||
warningMessageFtlId={MOCK_WARNING_MESSAGE_FTL_ID}
|
||||
warningType={MOCK_WARNING_TYPE}
|
||||
>
|
||||
{MOCK_WARNING_MESSAGE}
|
||||
</WarningMessage>
|
||||
);
|
||||
// testAllL10n(screen, bundle);
|
||||
|
||||
expect(screen.getByTestId('warning-message-container')).toHaveTextContent(
|
||||
'Beware: If you eat too many cookies, you might feel very sick.'
|
||||
);
|
||||
});
|
||||
});
|
|
@ -1,36 +0,0 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
import React from 'react';
|
||||
import { FtlMsg } from 'fxa-react/lib/utils';
|
||||
|
||||
type WarningMessageProps = {
|
||||
children: string;
|
||||
warningMessageFtlId: string;
|
||||
warningType: string;
|
||||
};
|
||||
|
||||
const WarningMessage = ({
|
||||
children,
|
||||
warningMessageFtlId,
|
||||
warningType,
|
||||
}: WarningMessageProps) => {
|
||||
return (
|
||||
<div className="mt-5 mb-8 text-xs" data-testid="warning-message-container">
|
||||
<FtlMsg
|
||||
id={warningMessageFtlId}
|
||||
elems={{
|
||||
span: <span className="text-red-600 uppercase">{warningType}</span>,
|
||||
}}
|
||||
>
|
||||
<p>
|
||||
<span className="text-red-600 uppercase">{warningType}</span>{' '}
|
||||
{children}
|
||||
</p>
|
||||
</FtlMsg>
|
||||
</div>
|
||||
);
|
||||
};
|
||||
|
||||
export default WarningMessage;
|
|
@ -1,8 +0,0 @@
|
|||
/* This Source Code Form is subject to the terms of the Mozilla Public
|
||||
* License, v. 2.0. If a copy of the MPL was not distributed with this
|
||||
* file, You can obtain one at http://mozilla.org/MPL/2.0/. */
|
||||
|
||||
export const MOCK_WARNING_MESSAGE_FTL_ID = 'warning-message-id';
|
||||
export const MOCK_WARNING_TYPE = 'Beware:';
|
||||
export const MOCK_WARNING_MESSAGE =
|
||||
'If you eat too many cookies, you might feel very sick.';
|
|
@ -9,11 +9,5 @@ complete-reset-password-success-alert = Password set
|
|||
# Displayed in an alert bar
|
||||
complete-reset-password-error-alert = Sorry, there was a problem setting your password
|
||||
|
||||
password-reset-data-may-not-be-recovered = Resetting your password may delete your encrypted browser data.
|
||||
password-reset-could-not-determine-account-recovery-key = Have an account recovery key?
|
||||
password-reset-use-account-recovery-key = Reset your password with your recovery key.
|
||||
password-reset-previously-signed-in-device = Have a device where you previously signed in?
|
||||
password-reset-data-may-be-saved-locally = Your browser data may be locally saved on that device. Sign in there with your new password to restore and sync.
|
||||
password-reset-no-old-device = Have a new device but don’t have your old one?
|
||||
password-reset-encrypted-data-cannot-be-recovered = We’re sorry, but your encrypted browser data on Firefox servers can’t be recovered.
|
||||
password-reset-learn-about-restoring-account-data = Learn more about restoring account data.
|
||||
password-reset-could-not-determine-account-recovery-key = Got your account recovery key?
|
||||
password-reset-use-account-recovery-key = Reset your password and keep your data
|
||||
|
|
|
@ -48,15 +48,13 @@ describe('CompleteResetPassword page', () => {
|
|||
|
||||
// Warning message about data loss should should be displayed
|
||||
expect(
|
||||
screen.getByText(
|
||||
'Resetting your password may delete your encrypted browser data.'
|
||||
)
|
||||
screen.getByText('Your browser data may not be recovered')
|
||||
).toBeVisible();
|
||||
|
||||
const inputs = screen.getAllByRole('textbox');
|
||||
expect(inputs).toHaveLength(2);
|
||||
expect(screen.getByLabelText('New password')).toBeVisible();
|
||||
expect(screen.getByLabelText('Re-enter password')).toBeVisible();
|
||||
expect(screen.getByLabelText('Confirm password')).toBeVisible();
|
||||
expect(
|
||||
screen.getByRole('button', { name: 'Create new password' })
|
||||
).toBeVisible();
|
||||
|
@ -84,14 +82,12 @@ describe('CompleteResetPassword page', () => {
|
|||
|
||||
// Warning messages about data loss should not be displayed.
|
||||
expect(
|
||||
screen.queryByText(
|
||||
'Resetting your password may delete your encrypted browser data.'
|
||||
)
|
||||
screen.queryByText('Your browser data may not be recovered')
|
||||
).not.toBeInTheDocument();
|
||||
|
||||
// Warning message about using recovery ke should not be displayed
|
||||
expect(
|
||||
screen.queryByText('Reset your password with your recovery key.')
|
||||
screen.queryByText('Reset your password and keep your data')
|
||||
).not.toBeInTheDocument();
|
||||
});
|
||||
|
||||
|
@ -117,20 +113,18 @@ describe('CompleteResetPassword page', () => {
|
|||
|
||||
// Warning messages about data loss should not be displayed.
|
||||
expect(
|
||||
screen.queryByText(
|
||||
'Resetting your password may delete your encrypted browser data.'
|
||||
)
|
||||
screen.queryByText('Your browser data may not be recovered')
|
||||
).not.toBeInTheDocument();
|
||||
|
||||
// Warning message about using recovery key should not be displayed
|
||||
expect(
|
||||
screen.queryByText('Reset your password with your recovery key.')
|
||||
screen.queryByText('Reset your password and keep your data')
|
||||
).not.toBeInTheDocument();
|
||||
|
||||
const inputs = screen.getAllByRole('textbox');
|
||||
expect(inputs).toHaveLength(2);
|
||||
expect(screen.getByLabelText('New password')).toBeVisible();
|
||||
expect(screen.getByLabelText('Re-enter password')).toBeVisible();
|
||||
expect(screen.getByLabelText('Confirm password')).toBeVisible();
|
||||
expect(
|
||||
screen.getByRole('button', { name: 'Create new password' })
|
||||
).toBeVisible();
|
||||
|
@ -151,7 +145,7 @@ describe('CompleteResetPassword page', () => {
|
|||
});
|
||||
});
|
||||
|
||||
describe('reset with unconfimred account recovery key', () => {
|
||||
describe('reset with unconfirmed account recovery key', () => {
|
||||
it('renders as expected', async () => {
|
||||
renderWithLocalizationProvider(
|
||||
<Subject
|
||||
|
@ -171,14 +165,12 @@ describe('CompleteResetPassword page', () => {
|
|||
|
||||
// Warning messages about data loss should not be displayed.
|
||||
expect(
|
||||
screen.queryByText(
|
||||
'Resetting your password may delete your encrypted browser data.'
|
||||
)
|
||||
screen.queryByText('Your browser data may not be recovered')
|
||||
).toBeInTheDocument();
|
||||
|
||||
// Warning message about using recovery key should be displayed
|
||||
expect(
|
||||
screen.queryByText('Reset your password with your recovery key.')
|
||||
screen.queryByText('Reset your password and keep your data')
|
||||
).not.toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
@ -203,14 +195,12 @@ describe('CompleteResetPassword page', () => {
|
|||
|
||||
// Warning messages about data loss should not be displayed.
|
||||
expect(
|
||||
screen.queryByText(
|
||||
'Resetting your password may delete your encrypted browser data.'
|
||||
)
|
||||
screen.queryByText('Your browser data may not be recovered')
|
||||
).not.toBeInTheDocument();
|
||||
|
||||
// Warning message about using recovery key should be displayed
|
||||
expect(
|
||||
screen.getByText('Reset your password with your recovery key.')
|
||||
screen.getByText('Reset your password and keep your data')
|
||||
).toBeVisible();
|
||||
});
|
||||
});
|
||||
|
@ -225,7 +215,7 @@ describe('CompleteResetPassword page', () => {
|
|||
user.type(screen.getByLabelText('New password'), MOCK_PASSWORD)
|
||||
);
|
||||
await waitFor(() =>
|
||||
user.type(screen.getByLabelText('Re-enter password'), MOCK_PASSWORD)
|
||||
user.type(screen.getByLabelText('Confirm password'), MOCK_PASSWORD)
|
||||
);
|
||||
const button = screen.getByRole('button', { name: 'Create new password' });
|
||||
expect(button).toBeEnabled();
|
||||
|
|
|
@ -11,9 +11,6 @@ import Banner, { BannerType } from '../../../components/Banner';
|
|||
import FormPasswordWithInlineCriteria from '../../../components/FormPasswordWithInlineCriteria';
|
||||
import LinkRememberPassword from '../../../components/LinkRememberPassword';
|
||||
import { ReactComponent as BangIcon } from './icon-bang.svg';
|
||||
import { ReactComponent as WarnIcon } from './icon-warn.svg';
|
||||
import { ReactComponent as IconNonSyncDevice } from './icon-non-sync-device.svg';
|
||||
import { ReactComponent as IconSyncDevice } from './icon-sync-device.svg';
|
||||
|
||||
import {
|
||||
CompleteResetPasswordFormData,
|
||||
|
@ -21,6 +18,7 @@ import {
|
|||
} from './interfaces';
|
||||
import { FtlMsg } from 'fxa-react/lib/utils';
|
||||
import { Link, useLocation } from '@reach/router';
|
||||
import ResetPasswordWarning from '../../../components/ResetPasswordWarning';
|
||||
|
||||
const CompleteResetPassword = ({
|
||||
email,
|
||||
|
@ -61,9 +59,11 @@ const CompleteResetPassword = ({
|
|||
|
||||
return (
|
||||
<AppLayout>
|
||||
<p className="text-start text-grey-400 text-sm">
|
||||
<FtlMsg id="password-reset-flow-heading">Reset your password</FtlMsg>
|
||||
</p>
|
||||
<FtlMsg id="password-reset-flow-heading">
|
||||
<p className="text-start text-grey-400 text-sm mb-6">
|
||||
Reset your password
|
||||
</p>
|
||||
</FtlMsg>
|
||||
|
||||
{/*
|
||||
In the event of serious error. A bright red banner will be displayed indicating
|
||||
|
@ -78,16 +78,15 @@ const CompleteResetPassword = ({
|
|||
*/}
|
||||
{hasConfirmedRecoveryKey === false && recoveryKeyExists === undefined && (
|
||||
<div
|
||||
className={`bg-red-100 rounded-lg text-sm mt-6 text-left rtl:text-right p-3`}
|
||||
className="flex bg-red-50 rounded-sm text-xs text-start p-3"
|
||||
data-testid="warning-message-container"
|
||||
>
|
||||
<div className="flex">
|
||||
<BangIcon role="img" className="flex-initial me-2 mt-1" />
|
||||
<div className="flex-1 text-xs">
|
||||
<FtlMsg id="password-reset-could-not-determine-account-recovery-key">
|
||||
Have an account recovery key?
|
||||
</FtlMsg>{' '}
|
||||
<br />
|
||||
<BangIcon role="img" className="flex-initial me-2 mt-1" />
|
||||
<div className="flex-1">
|
||||
<FtlMsg id="password-reset-could-not-determine-account-recovery-key">
|
||||
<p>Got your account recovery key?</p>
|
||||
</FtlMsg>
|
||||
<FtlMsg id="password-reset-use-account-recovery-key">
|
||||
<Link
|
||||
to={`/account_recovery_confirm_key${location.search}`}
|
||||
state={locationState}
|
||||
|
@ -96,69 +95,16 @@ const CompleteResetPassword = ({
|
|||
GleanMetrics.passwordReset.createNewRecoveryKeyMessageClick()
|
||||
}
|
||||
>
|
||||
<FtlMsg id="password-reset-use-account-recovery-key">
|
||||
Reset your password with your recovery key.
|
||||
</FtlMsg>
|
||||
</Link>{' '}
|
||||
</div>
|
||||
Reset your password and keep your data
|
||||
</Link>
|
||||
</FtlMsg>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
|
||||
{hasConfirmedRecoveryKey === false &&
|
||||
recoveryKeyExists !== undefined &&
|
||||
hasSyncDevices && (
|
||||
<div
|
||||
className={`bg-orange-50 rounded-lg text-sm mt-6 text-left rtl:text-right p-4 border-transparent`}
|
||||
data-testid="warning-message-container"
|
||||
>
|
||||
<div className="flex font-semibold">
|
||||
<WarnIcon role="img" className="flex-initial me-2 mt-1" />
|
||||
<h1 className="flex-1">
|
||||
<FtlMsg id="password-reset-data-may-not-be-recovered">
|
||||
Resetting your password may delete your encrypted browser
|
||||
data.
|
||||
</FtlMsg>
|
||||
</h1>
|
||||
</div>
|
||||
<div className="ps-4">
|
||||
<p className="font-semibold pt-4">
|
||||
<IconSyncDevice role="img" className="inline-block mr-2" />
|
||||
<FtlMsg id="password-reset-previously-signed-in-device">
|
||||
Have a device where you previously signed in?
|
||||
</FtlMsg>
|
||||
</p>
|
||||
<p className="ps-6 text-xs">
|
||||
<FtlMsg id="password-reset-data-maybe-saved-locally">
|
||||
Your browser data may be locally saved on that device. Sign in
|
||||
there with your new password to restore and sync.
|
||||
</FtlMsg>
|
||||
</p>
|
||||
<p className="font-semibold pt-4">
|
||||
<IconNonSyncDevice role="img" className="inline-block mr-2" />
|
||||
<FtlMsg id="password-reset-no-old-device">
|
||||
Have a new device but don’t have your old one?
|
||||
</FtlMsg>
|
||||
</p>
|
||||
<p className="ps-6 text-xs">
|
||||
<FtlMsg id="password-reset-encrypted-data-cannot-be-recovered">
|
||||
We’re sorry, but your encrypted browser data on Firefox
|
||||
servers can’t be recovered.
|
||||
</FtlMsg>
|
||||
</p>
|
||||
<p className="ps-6 text-xs mt-4">
|
||||
<a
|
||||
href="https://support.mozilla.org/en-US/kb/how-reset-your-password-without-account-recovery-keys-access-data"
|
||||
className="link-blue"
|
||||
>
|
||||
<FtlMsg id="password-reset-learn-about-restoring-account-data">
|
||||
Learn more about restoring account data.
|
||||
</FtlMsg>
|
||||
</a>
|
||||
</p>
|
||||
</div>
|
||||
</div>
|
||||
)}
|
||||
hasSyncDevices && <ResetPasswordWarning />}
|
||||
{/*
|
||||
Hidden email field is to allow Fx password manager
|
||||
to correctly save the updated password. Without it,
|
||||
|
@ -167,9 +113,11 @@ const CompleteResetPassword = ({
|
|||
*/}
|
||||
<input type="email" value={email} className="hidden" readOnly />
|
||||
|
||||
<h1 className="font-semibold text-xl text-start mt-6">
|
||||
<FtlMsg id="complete-reset-pw-header-v2">Create a new password</FtlMsg>
|
||||
</h1>
|
||||
<FtlMsg id="complete-reset-pw-header-v2">
|
||||
<h1 className="font-semibold text-xl text-start mt-6">
|
||||
Create a new password
|
||||
</h1>
|
||||
</FtlMsg>
|
||||
<section className="text-start mt-2">
|
||||
<FormPasswordWithInlineCriteria
|
||||
{...{
|
||||
|
|