зеркало из https://github.com/mozilla/fxa.git
feat(ux): Update 2fa signin screens/reset PW copy, create HeadingPrimary
Because: * We are prepping for SMS work and want to make some small UX improvements This commit: * Creates HeadingPrimary for our grey h1 text at the top of our flows that we are moving towards * Updates copy and styling for 2FA signin and reset password closes FXA-10210
This commit is contained in:
Родитель
616c182a13
Коммит
d722c1f7eb
|
@ -194,7 +194,7 @@ export class ResetPasswordPage extends BaseLayout {
|
|||
}
|
||||
|
||||
async fillOutTotpForm(code: string) {
|
||||
await this.page.getByLabel('Enter code').fill(code);
|
||||
await this.page.getByLabel('Enter 6-digit code').fill(code);
|
||||
return this.page.getByRole('button', { name: 'Confirm' }).click();
|
||||
}
|
||||
|
||||
|
@ -203,9 +203,7 @@ export class ResetPasswordPage extends BaseLayout {
|
|||
}
|
||||
|
||||
async fillOurRecoveryCodeForm(code: string) {
|
||||
await this.page
|
||||
.getByLabel('Enter 10-digit backup authentication code')
|
||||
.fill(code);
|
||||
await this.page.getByLabel('Enter 10-character code').fill(code);
|
||||
return this.page.getByRole('button', { name: 'Confirm' }).click();
|
||||
}
|
||||
|
||||
|
|
|
@ -10,7 +10,7 @@ export class SigninRecoveryCodePage extends BaseTokenCodePage {
|
|||
get codeInput() {
|
||||
this.checkPath();
|
||||
return this.page
|
||||
.getByLabel('Enter 10-digit backup') // React
|
||||
.getByLabel('Enter 10-character code') // React
|
||||
.or(this.page.getByPlaceholder('Enter 10-digit backup')); //Backbone
|
||||
}
|
||||
}
|
||||
|
|
|
@ -10,7 +10,7 @@ export class SigninTotpCodePage extends BaseTokenCodePage {
|
|||
get codeInput() {
|
||||
this.checkPath();
|
||||
return this.page
|
||||
.getByLabel('Enter code') // React
|
||||
.getByLabel('Enter 6-digit code') // React
|
||||
.or(this.page.getByPlaceholder('Enter 6-digit code')); //Backbone
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,14 @@
|
|||
/* 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 { HeadingPrimary } from '.';
|
||||
import { Meta } from '@storybook/react';
|
||||
|
||||
export default {
|
||||
title: 'Components/HeadingPrimary',
|
||||
component: HeadingPrimary,
|
||||
} as Meta;
|
||||
|
||||
export const Default = <HeadingPrimary>Primary heading text</HeadingPrimary>;
|
|
@ -0,0 +1,13 @@
|
|||
/* 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';
|
||||
|
||||
export const HeadingPrimary = ({
|
||||
children,
|
||||
marginClass = 'mb-5',
|
||||
}: {
|
||||
children: React.ReactNode;
|
||||
marginClass?: string;
|
||||
}) => <h1 className={`${marginClass} text-grey-400 text-base`}>{children}</h1>;
|
|
@ -8,6 +8,7 @@ import { FtlMsg } from 'fxa-react/lib/utils';
|
|||
import { CreateRecoveryKeyHandler } from '../../pages/InlineRecoveryKeySetup/interfaces';
|
||||
import Banner from '../Banner';
|
||||
import { useFtlMsgResolver } from '../../models';
|
||||
import { HeadingPrimary } from '../HeadingPrimary';
|
||||
|
||||
export const InlineRecoveryKeySetupCreate = ({
|
||||
createRecoveryKeyHandler,
|
||||
|
@ -50,11 +51,9 @@ export const InlineRecoveryKeySetupCreate = ({
|
|||
content={{ localizedHeading: localizedErrorBannerMessage }}
|
||||
/>
|
||||
)}
|
||||
<h1 className="text-grey-400 mb-3 mt-5">
|
||||
<FtlMsg id="inline-recovery-key-setup-create-header">
|
||||
Secure your account
|
||||
</FtlMsg>
|
||||
</h1>
|
||||
<FtlMsg id="inline-recovery-key-setup-create-header">
|
||||
<HeadingPrimary>Secure your account</HeadingPrimary>
|
||||
</FtlMsg>
|
||||
|
||||
<RecoveryKeyImage className="my-6 mx-auto" />
|
||||
|
||||
|
|
|
@ -14,6 +14,7 @@ import { InlineRecoveryKeySetupProps } from './interfaces';
|
|||
import RecoveryKeySetupHint from '../../components/RecoveryKeySetupHint';
|
||||
import Banner from '../../components/Banner';
|
||||
import { useFtlMsgResolver } from '../../models';
|
||||
import { HeadingPrimary } from '../../components/HeadingPrimary';
|
||||
|
||||
const viewName = 'inline-recovery-key-setup';
|
||||
|
||||
|
@ -43,11 +44,9 @@ export const InlineRecoveryKeySetup = ({
|
|||
case 3:
|
||||
return (
|
||||
<>
|
||||
<h1 className="text-grey-400">
|
||||
<FtlMsg id="inline-recovery-key-setup-hint-header">
|
||||
Security recommendation
|
||||
</FtlMsg>
|
||||
</h1>
|
||||
<FtlMsg id="inline-recovery-key-setup-hint-header">
|
||||
<HeadingPrimary>Security recommendation</HeadingPrimary>
|
||||
</FtlMsg>
|
||||
<RecoveryKeySetupHint
|
||||
{...{ viewName }}
|
||||
navigateForward={() => {
|
||||
|
@ -69,11 +68,9 @@ export const InlineRecoveryKeySetup = ({
|
|||
),
|
||||
}}
|
||||
/>
|
||||
<h1 className="text-grey-400 mb-3 mt-5">
|
||||
<FtlMsg id="inline-recovery-key-setup-download-header">
|
||||
Secure your account
|
||||
</FtlMsg>
|
||||
</h1>
|
||||
<FtlMsg id="inline-recovery-key-setup-download-header">
|
||||
<HeadingPrimary>Secure your account</HeadingPrimary>
|
||||
</FtlMsg>
|
||||
<RecoveryKeyImage className="my-6 mx-auto" />
|
||||
|
||||
<h2 className="font-bold text-xl mb-5">
|
||||
|
|
|
@ -22,6 +22,7 @@ import { getLocalizedErrorMessage } from '../../../lib/error-utils';
|
|||
import { RecoveryKeyImage } from '../../../components/images';
|
||||
import { Constants } from '../../../lib/constants';
|
||||
import Banner from '../../../components/Banner';
|
||||
import { HeadingPrimary } from '../../../components/HeadingPrimary';
|
||||
|
||||
// TODO in FXA-7894 use sensitive data client to pass sensitive data
|
||||
// Depends on FXA-7400
|
||||
|
@ -138,23 +139,19 @@ const AccountRecoveryConfirmKey = ({
|
|||
};
|
||||
|
||||
return (
|
||||
<AppLayout>
|
||||
<AppLayout cardClass="card-base">
|
||||
<FtlMsg id="password-reset-flow-heading">
|
||||
<h1 className="text-start text-grey-400 text-sm">
|
||||
Reset your password
|
||||
</h1>
|
||||
<HeadingPrimary>Reset your password</HeadingPrimary>
|
||||
</FtlMsg>
|
||||
{errorMessage && (
|
||||
<Banner type="error" content={{ localizedHeading: errorMessage }} />
|
||||
)}
|
||||
<RecoveryKeyImage className="mx-auto my-2" />
|
||||
<FtlMsg id="account-recovery-confirm-key-heading">
|
||||
<h2 className="card-header text-start mb-2">
|
||||
Enter your account recovery key
|
||||
</h2>
|
||||
<h2 className="card-header mb-2">Enter your account recovery key</h2>
|
||||
</FtlMsg>
|
||||
<FtlMsg id="account-recovery-confirm-key-instruction">
|
||||
<p className="text-start text-sm">
|
||||
<p className="text-sm">
|
||||
This key recovers your encrypted browsing data, such as passwords and
|
||||
bookmarks, from Firefox servers.
|
||||
</p>
|
||||
|
@ -190,7 +187,7 @@ const AccountRecoveryConfirmKey = ({
|
|||
</FtlMsg>
|
||||
|
||||
{recoveryKeyHint && (
|
||||
<div className="bg-grey-50 p-4 text-start text-sm rounded-md">
|
||||
<div className="bg-grey-50 p-4 text-sm rounded-md">
|
||||
<FtlMsg id="account-recovery-confirm-key-hint">
|
||||
<p className="text-grey-500">Your storage hint is:</p>
|
||||
</FtlMsg>
|
||||
|
|
|
@ -18,6 +18,7 @@ import { FtlMsg } from 'fxa-react/lib/utils';
|
|||
import ResetPasswordWarning from '../../../components/ResetPasswordWarning';
|
||||
import { Link, useLocation } from '@reach/router';
|
||||
import Banner from '../../../components/Banner';
|
||||
import { HeadingPrimary } from '../../../components/HeadingPrimary';
|
||||
|
||||
const CompleteResetPassword = ({
|
||||
email,
|
||||
|
@ -63,11 +64,9 @@ const CompleteResetPassword = ({
|
|||
};
|
||||
|
||||
return (
|
||||
<AppLayout>
|
||||
<AppLayout cardClass="card-base">
|
||||
<FtlMsg id="password-reset-flow-heading">
|
||||
<p className="text-start text-grey-400 text-sm mb-6">
|
||||
Reset your password
|
||||
</p>
|
||||
<HeadingPrimary>Reset your password</HeadingPrimary>
|
||||
</FtlMsg>
|
||||
|
||||
{/*
|
||||
|
@ -92,11 +91,9 @@ const CompleteResetPassword = ({
|
|||
<input type="email" value={email} className="hidden" readOnly />
|
||||
|
||||
<FtlMsg id="complete-reset-pw-header-v2">
|
||||
<h1 className="font-semibold text-xl text-start mt-6">
|
||||
Create a new password
|
||||
</h1>
|
||||
<h1 className="font-semibold text-xl mt-6">Create a new password</h1>
|
||||
</FtlMsg>
|
||||
<section className="text-start mt-2">
|
||||
<section className="mt-2">
|
||||
<FormPasswordWithInlineCriteria
|
||||
{...{
|
||||
email,
|
||||
|
|
|
@ -14,6 +14,7 @@ import { ResendStatus } from '../../../lib/types';
|
|||
import { EmailCodeImage } from '../../../components/images';
|
||||
import GleanMetrics from '../../../lib/glean';
|
||||
import Banner, { ResendCodeSuccessBanner } from '../../../components/Banner';
|
||||
import { HeadingPrimary } from '../../../components/HeadingPrimary';
|
||||
|
||||
const ConfirmResetPassword = ({
|
||||
clearBanners,
|
||||
|
@ -43,9 +44,9 @@ const ConfirmResetPassword = ({
|
|||
};
|
||||
|
||||
return (
|
||||
<AppLayout>
|
||||
<AppLayout cardClass="card-base">
|
||||
<FtlMsg id="password-reset-flow-heading">
|
||||
<p className="text-start text-grey-400 text-sm">Reset your password</p>
|
||||
<HeadingPrimary marginClass="">Reset your password</HeadingPrimary>
|
||||
</FtlMsg>
|
||||
{resendStatus === ResendStatus.sent && !hasResendError && (
|
||||
<ResendCodeSuccessBanner />
|
||||
|
@ -61,16 +62,14 @@ const ConfirmResetPassword = ({
|
|||
)}
|
||||
<EmailCodeImage className="mx-auto" />
|
||||
<FtlMsg id="confirm-reset-password-with-code-heading">
|
||||
<h2 className="card-header text-start my-4">Check your email</h2>
|
||||
<h2 className="card-header my-4">Check your email</h2>
|
||||
</FtlMsg>
|
||||
<FtlMsg
|
||||
id="confirm-reset-password-with-code-instruction"
|
||||
vars={{ email }}
|
||||
elems={{ span: spanElement }}
|
||||
>
|
||||
<p className="text-start">
|
||||
We sent a confirmation code to {spanElement}.
|
||||
</p>
|
||||
<p>We sent a confirmation code to {spanElement}.</p>
|
||||
</FtlMsg>
|
||||
<FormVerifyTotp
|
||||
codeLength={8}
|
||||
|
@ -91,7 +90,7 @@ const ConfirmResetPassword = ({
|
|||
}}
|
||||
/>
|
||||
<LinkRememberPassword {...{ email }} clickHandler={signinClickHandler} />
|
||||
<div className="flex justify-between mt-4 text-sm">
|
||||
<div className="flex justify-between mt-5 text-sm">
|
||||
<FtlMsg id="confirm-reset-password-otp-resend-code-button">
|
||||
<button type="button" className="link-blue" onClick={resendCode}>
|
||||
Resend code
|
||||
|
|
|
@ -1,9 +1,11 @@
|
|||
## PasswordResetConfirmTotp Page
|
||||
|
||||
confirm-totp-reset-password-header = Reset your password
|
||||
confirm-totp-reset-password-subheader = Enter your two-factor authentication security code (2FA)
|
||||
confirm-totp-reset-password-instruction = Check your authenticator app to reset your password.
|
||||
confirm-totp-reset-password-subheader-v2 = Enter two-step authentication code
|
||||
confirm-totp-reset-password-instruction-v2 = Check your <strong>authenticator app</strong> to reset your password.
|
||||
confirm-totp-reset-password-trouble-code = Trouble entering code?
|
||||
confirm-totp-reset-password-confirm-button = Confirm
|
||||
confirm-totp-reset-password-input-label = Enter code
|
||||
confirm-totp-reset-password-use-different-account = Use a different account
|
||||
confirm-totp-reset-password-input-label-v2 = Enter 6-digit code
|
||||
confirm-totp-reset-password-use-different-account = Use a different account
|
||||
confirm-recovery-code-reset-password-input-label = Enter 10-character code
|
||||
confirm-recovery-code-reset-password-trouble-code = Back
|
||||
|
|
|
@ -30,14 +30,15 @@ describe('ConfirmTotpResetPassword', () => {
|
|||
).toBeVisible();
|
||||
|
||||
expect(screen.getByRole('heading', { level: 2 })).toHaveTextContent(
|
||||
'Enter your two-factor authentication security code (2FA)'
|
||||
'Enter two-step authentication code'
|
||||
);
|
||||
|
||||
expect(screen.getByRole('textbox', { name: 'Enter code' })).toBeVisible();
|
||||
|
||||
expect(
|
||||
screen.getByText('Check your authenticator app to reset your password.')
|
||||
screen.getByRole('textbox', { name: 'Enter 6-digit code' })
|
||||
).toBeVisible();
|
||||
|
||||
screen.getByText('authenticator app', { exact: false });
|
||||
screen.getByText('to reset your password', { exact: false });
|
||||
expect(screen.getByRole('button', { name: 'Confirm' })).toBeVisible();
|
||||
expect(screen.getByText('Trouble entering code?')).toBeVisible();
|
||||
});
|
||||
|
@ -47,7 +48,7 @@ describe('ConfirmTotpResetPassword', () => {
|
|||
renderWithLocalizationProvider(<Subject verifyCode={mockVerifyCode} />);
|
||||
|
||||
await waitFor(() =>
|
||||
screen.getByRole('textbox', { name: 'Enter code' }).click()
|
||||
screen.getByRole('textbox', { name: 'Enter 6-digit code' }).click()
|
||||
);
|
||||
await waitFor(() => {
|
||||
user.paste('123456');
|
||||
|
|
|
@ -11,6 +11,7 @@ import FormVerifyCode, {
|
|||
commonBackupCodeFormAttributes,
|
||||
FormAttributes,
|
||||
} from '../../../components/FormVerifyCode';
|
||||
import { HeadingPrimary } from '../../../components/HeadingPrimary';
|
||||
|
||||
export type ConfirmTotpResetPasswordProps = {
|
||||
verifyCode: (code: string) => Promise<void>;
|
||||
|
@ -29,8 +30,8 @@ const ConfirmTotpResetPassword = ({
|
|||
const [showRecoveryCode, setShowRecoveryCode] = useState<boolean>(false);
|
||||
|
||||
const totpFormAttributes: FormAttributes = {
|
||||
inputFtlId: 'confirm-totp-reset-password-input-label',
|
||||
inputLabelText: 'Enter code',
|
||||
inputFtlId: 'confirm-totp-reset-password-input-label-v2',
|
||||
inputLabelText: 'Enter 6-digit code',
|
||||
pattern: '[0-9]{6}',
|
||||
maxLength: 6,
|
||||
submitButtonFtlId: 'confirm-totp-reset-password-confirm-button',
|
||||
|
@ -39,7 +40,7 @@ const ConfirmTotpResetPassword = ({
|
|||
|
||||
const recoveryCodeFormAttributes: FormAttributes = {
|
||||
inputFtlId: 'confirm-recovery-code-reset-password-input-label',
|
||||
inputLabelText: 'Enter 10-digit backup authentication code',
|
||||
inputLabelText: 'Enter 10-character code',
|
||||
submitButtonFtlId: 'confirm-totp-reset-password-confirm-button',
|
||||
submitButtonText: 'Confirm',
|
||||
...commonBackupCodeFormAttributes,
|
||||
|
@ -54,13 +55,11 @@ const ConfirmTotpResetPassword = ({
|
|||
<>
|
||||
{showRecoveryCode ? (
|
||||
<AppLayout cardClass="card-base">
|
||||
<h1 className="text-grey-400 mb-6 text-start">
|
||||
<FtlMsg id="confirm-totp-reset-password-header">
|
||||
Reset your password
|
||||
</FtlMsg>
|
||||
</h1>
|
||||
<FtlMsg id="confirm-totp-reset-password-header">
|
||||
<HeadingPrimary>Reset your password</HeadingPrimary>
|
||||
</FtlMsg>
|
||||
|
||||
<h2 className="font-bold text-xl text-start">
|
||||
<h2 className="font-bold text-xl">
|
||||
<FtlMsg id="confirm-totp-reset-password-subheader">
|
||||
Enter your backup recovery code
|
||||
</FtlMsg>
|
||||
|
@ -68,7 +67,7 @@ const ConfirmTotpResetPassword = ({
|
|||
|
||||
<div className="flex space-x-4">
|
||||
<img src={protectionShieldIcon} alt="" />
|
||||
<p className="my-5 text-md text-start">
|
||||
<p className="my-5 text-md">
|
||||
<FtlMsg id="confirm-totp-reset-password-instruction">
|
||||
Check your download or saved backup recovery code.
|
||||
</FtlMsg>
|
||||
|
@ -103,25 +102,24 @@ const ConfirmTotpResetPassword = ({
|
|||
</AppLayout>
|
||||
) : (
|
||||
<AppLayout cardClass="card-base">
|
||||
<h1 className="text-grey-400 mb-6 text-start">
|
||||
<FtlMsg id="confirm-totp-reset-password-header">
|
||||
Reset your password
|
||||
</FtlMsg>
|
||||
</h1>
|
||||
<FtlMsg id="confirm-totp-reset-password-header">
|
||||
<HeadingPrimary>Reset your password</HeadingPrimary>
|
||||
</FtlMsg>
|
||||
|
||||
<h2 className="font-bold text-xl text-start">
|
||||
<FtlMsg id="confirm-totp-reset-password-subheader">
|
||||
Enter your two-factor authentication security code (2FA)
|
||||
<h2 className="font-bold text-xl">
|
||||
<FtlMsg id="confirm-totp-reset-password-subheader-v2">
|
||||
Enter two-step authentication code
|
||||
</FtlMsg>
|
||||
</h2>
|
||||
|
||||
<div className="flex space-x-4">
|
||||
<img src={protectionShieldIcon} alt="" />
|
||||
<p className="my-5 text-md text-start">
|
||||
<FtlMsg id="confirm-totp-reset-password-instruction">
|
||||
Check your authenticator app to reset your password.
|
||||
</FtlMsg>
|
||||
</p>
|
||||
<FtlMsg id="confirm-totp-reset-password-instruction-v2">
|
||||
<p className="my-5 text-md">
|
||||
Check your <strong>authenticator app</strong> to reset your
|
||||
password.
|
||||
</p>
|
||||
</FtlMsg>
|
||||
</div>
|
||||
|
||||
<FormVerifyCode
|
||||
|
|
|
@ -99,7 +99,7 @@ const ResetPassword = ({
|
|||
|
||||
<form
|
||||
noValidate
|
||||
className="flex flex-col gap-4 mb-4"
|
||||
className="flex flex-col gap-4 mb-5"
|
||||
onSubmit={handleSubmit(onSubmit)}
|
||||
>
|
||||
<FtlMsg id="password-reset-email-input" attrs={{ label: true }}>
|
||||
|
|
|
@ -3,15 +3,10 @@
|
|||
## (provided to the user when they first set up two-step authentication)
|
||||
## when they are unable to sign in with two-step authentication (e.g., Authy, Duo, etc.)
|
||||
|
||||
# String within the <span> element appears on a separate line
|
||||
# If more appropriate in a locale, the string within the <span>, "to continue to account settings" can stand alone as "Continue to account settings"
|
||||
signin-recovery-code-heading-w-default-service = Enter backup authentication code <span>to continue to account settings</span>
|
||||
# String within the <span> element appears on a separate line
|
||||
# If more appropriate in a locale, the string within the <span>, "to continue to { $serviceName }" can stand alone as "Continue to { $serviceName }"
|
||||
# { $serviceName } represents a product name (e.g., Mozilla VPN) that will be passed in as a variable
|
||||
signin-recovery-code-heading-w-custom-service = Enter backup authentication code <span>to continue to { $serviceName }</span>
|
||||
signin-recovery-code-instruction = Please enter a backup authentication code that was provided to you during two step authentication setup.
|
||||
signin-recovery-code-input-label = Enter 10-digit backup authentication code
|
||||
signin-recovery-code-heading = Sign in
|
||||
signin-recovery-code-sub-heading = Enter backup authentication code
|
||||
signin-recovery-code-instruction-v2 = Enter one of the one-time use backup authentication codes you saved during two-step authentication setup.
|
||||
signin-recovery-code-input-label-v2 = Enter 10-character code
|
||||
# Form button to confirm if the backup authentication code entered by the user is valid
|
||||
signin-recovery-code-confirm-button = Confirm
|
||||
# Link to return to signin with two-step authentication code
|
||||
|
|
|
@ -51,16 +51,18 @@ describe('PageSigninRecoveryCode', () => {
|
|||
</LocationProvider>
|
||||
);
|
||||
|
||||
const headingEl = screen.getByRole('heading', { level: 1 });
|
||||
expect(headingEl).toHaveTextContent(
|
||||
'Enter backup authentication code to continue to account settings'
|
||||
expect(screen.getByRole('heading', { level: 1 })).toHaveTextContent(
|
||||
'Sign in'
|
||||
);
|
||||
expect(screen.getByRole('heading', { level: 2 })).toHaveTextContent(
|
||||
'Enter backup authentication code'
|
||||
);
|
||||
screen.getByRole('img', { name: 'Document that contains hidden text.' });
|
||||
screen.getByText(
|
||||
'Please enter a backup authentication code that was provided to you during two step authentication setup.'
|
||||
'Enter one of the one-time use backup authentication codes you saved during two-step authentication setup.'
|
||||
);
|
||||
screen.getByRole('textbox', {
|
||||
name: 'Enter 10-digit backup authentication code',
|
||||
name: 'Enter 10-character code',
|
||||
});
|
||||
|
||||
screen.getByRole('button', { name: 'Confirm' });
|
||||
|
@ -70,25 +72,6 @@ describe('PageSigninRecoveryCode', () => {
|
|||
});
|
||||
});
|
||||
|
||||
it('shows the relying party in the header when a service name is provided', () => {
|
||||
const mockSubmitRecoveryCode = jest.fn();
|
||||
renderWithLocalizationProvider(
|
||||
<LocationProvider>
|
||||
<SigninRecoveryCode
|
||||
finishOAuthFlowHandler={mockFinishOAuthFlowHandler}
|
||||
integration={mockIntegration}
|
||||
signinState={mockSigninLocationState}
|
||||
submitRecoveryCode={mockSubmitRecoveryCode}
|
||||
serviceName={MozServices.MozillaVPN}
|
||||
/>
|
||||
</LocationProvider>
|
||||
);
|
||||
const headingEl = screen.getByRole('heading', { level: 1 });
|
||||
expect(headingEl).toHaveTextContent(
|
||||
'Enter backup authentication code to continue to Mozilla VPN'
|
||||
);
|
||||
});
|
||||
|
||||
describe('metrics', () => {
|
||||
it('emits a metrics event on render', () => {
|
||||
const mockSubmitRecoveryCode = jest.fn();
|
||||
|
|
|
@ -7,7 +7,6 @@ import { Link, RouteComponentProps, useLocation } from '@reach/router';
|
|||
import { FtlMsg } from 'fxa-react/lib/utils';
|
||||
import { isWebIntegration, useFtlMsgResolver } from '../../../models';
|
||||
import { BackupCodesImage } from '../../../components/images';
|
||||
import CardHeader from '../../../components/CardHeader';
|
||||
import LinkExternal from 'fxa-react/components/LinkExternal';
|
||||
import FormVerifyCode, {
|
||||
FormAttributes,
|
||||
|
@ -23,6 +22,7 @@ import { getLocalizedErrorMessage } from '../../../lib/error-utils';
|
|||
import { useWebRedirect } from '../../../lib/hooks/useWebRedirect';
|
||||
import { isBase32Crockford } from '../../../lib/utilities';
|
||||
import Banner from '../../../components/Banner';
|
||||
import { HeadingPrimary } from '../../../components/HeadingPrimary';
|
||||
|
||||
export const viewName = 'signin-recovery-code';
|
||||
|
||||
|
@ -56,8 +56,8 @@ const SigninRecoveryCode = ({
|
|||
: '';
|
||||
|
||||
const formAttributes: FormAttributes = {
|
||||
inputFtlId: 'signin-recovery-code-input-label',
|
||||
inputLabelText: 'Enter 10-digit backup authentication code',
|
||||
inputFtlId: 'signin-recovery-code-input-label-v2',
|
||||
inputLabelText: 'Enter 10-character code',
|
||||
inputMode: InputModeEnum.text,
|
||||
pattern: '[a-zA-Z0-9]',
|
||||
maxLength: 10,
|
||||
|
@ -150,13 +150,10 @@ const SigninRecoveryCode = ({
|
|||
};
|
||||
|
||||
return (
|
||||
<AppLayout>
|
||||
<CardHeader
|
||||
headingWithDefaultServiceFtlId="signin-recovery-code-heading-w-default-service"
|
||||
headingWithCustomServiceFtlId="signin-recovery-code-heading-w-custom-service"
|
||||
headingText="Enter backup authentication code"
|
||||
{...{ serviceName }}
|
||||
/>
|
||||
<AppLayout cardClass="card-base">
|
||||
<FtlMsg id="signin-recovery-code-heading">
|
||||
<HeadingPrimary>Sign in</HeadingPrimary>
|
||||
</FtlMsg>
|
||||
|
||||
{bannerErrorMessage && (
|
||||
<Banner
|
||||
|
@ -164,14 +161,19 @@ const SigninRecoveryCode = ({
|
|||
content={{ localizedHeading: bannerErrorMessage }}
|
||||
/>
|
||||
)}
|
||||
|
||||
<div className="flex justify-center mx-auto">
|
||||
<BackupCodesImage className="w-3/5" />
|
||||
</div>
|
||||
|
||||
<FtlMsg id="signin-recovery-code-instruction">
|
||||
<p className="m-5 text-sm">
|
||||
Please enter a backup authentication code that was provided to you
|
||||
during two step authentication setup.
|
||||
<FtlMsg id="signin-recovery-code-sub-heading">
|
||||
<h2 className="card-header">Enter backup authentication code</h2>
|
||||
</FtlMsg>
|
||||
|
||||
<FtlMsg id="signin-recovery-code-instruction-v2">
|
||||
<p className="mt-2 text-sm">
|
||||
Enter one of the one-time use backup authentication codes you saved
|
||||
during two-step authentication setup.
|
||||
</p>
|
||||
</FtlMsg>
|
||||
|
||||
|
@ -186,7 +188,7 @@ const SigninRecoveryCode = ({
|
|||
}}
|
||||
/>
|
||||
|
||||
<div className="mt-5 link-blue text-sm flex justify-between">
|
||||
<div className="mt-10 link-blue text-sm flex justify-between">
|
||||
<FtlMsg id="signin-recovery-code-back-link">
|
||||
<Link
|
||||
to={`/signin_totp_code${location.search || ''}`}
|
||||
|
|
|
@ -2,13 +2,13 @@
|
|||
## TOTP (time-based one-time password) is a form of two-factor authentication (2FA).
|
||||
## Users that have set up two-factor authentication land on this page during sign-in.
|
||||
|
||||
signin-totp-code-subheader = Enter your two-factor authentication security code (2FA)
|
||||
signin-totp-code-instruction-v3 = Check your authenticator app to confirm your sign-in.
|
||||
signin-totp-code-input-label-v3 = Enter code
|
||||
signin-totp-code-subheader-v2 = Enter two-step authentication code
|
||||
signin-totp-code-instruction-v4 = Check your <strong>authenticator app</strong> to confirm your sign-in.
|
||||
signin-totp-code-input-label-v4 = Enter 6-digit code
|
||||
|
||||
# Form button to confirm if the authentication code entered by the user is valid
|
||||
signin-totp-code-confirm-button = Confirm
|
||||
signin-totp-code-other-account-link = Use a different account
|
||||
signin-totp-code-recovery-code-link = Trouble entering code?
|
||||
# Error displayed in a tooltip when the form is submitted without a code
|
||||
signin-totp-code-required-error = Authentication code required
|
||||
signin-totp-code-required-error = Authentication code required
|
||||
|
|
|
@ -79,10 +79,8 @@ describe('Sign in with TOTP code page', () => {
|
|||
// testAllL10n(screen, bundle);
|
||||
|
||||
const headingEl = screen.getByRole('heading', { level: 2 });
|
||||
expect(headingEl).toHaveTextContent(
|
||||
'Enter your two-factor authentication security code (2FA)'
|
||||
);
|
||||
screen.getByLabelText('Enter code');
|
||||
expect(headingEl).toHaveTextContent('Enter two-step authentication code');
|
||||
screen.getByLabelText('Enter 6-digit code');
|
||||
|
||||
screen.getByRole('button', { name: 'Confirm' });
|
||||
screen.getByRole('link', { name: 'Use a different account' });
|
||||
|
@ -98,9 +96,7 @@ describe('Sign in with TOTP code page', () => {
|
|||
/>
|
||||
);
|
||||
const headingEl = screen.getByRole('heading', { level: 2 });
|
||||
expect(headingEl).toHaveTextContent(
|
||||
'Enter your two-factor authentication security code (2FA)'
|
||||
);
|
||||
expect(headingEl).toHaveTextContent('Enter two-step authentication code');
|
||||
});
|
||||
|
||||
it('emits a metrics event on render', () => {
|
||||
|
@ -132,7 +128,7 @@ describe('Sign in with TOTP code page', () => {
|
|||
/>
|
||||
);
|
||||
|
||||
fireEvent.input(screen.getByLabelText('Enter code'), {
|
||||
fireEvent.input(screen.getByLabelText('Enter 6-digit code'), {
|
||||
target: { value: '123456' },
|
||||
});
|
||||
screen.getByRole('button', { name: 'Confirm' }).click();
|
||||
|
|
|
@ -25,6 +25,7 @@ import {
|
|||
import protectionShieldIcon from '@fxa/shared/assets/images/protection-shield.svg';
|
||||
import Banner from '../../../components/Banner';
|
||||
import { SensitiveDataClientAuthKeys } from '../../../lib/sensitive-data-client';
|
||||
import { HeadingPrimary } from '../../../components/HeadingPrimary';
|
||||
|
||||
// TODO: show a banner success message if a user is coming from reset password
|
||||
// in FXA-6491. This differs from content-server where currently, users only
|
||||
|
@ -74,8 +75,8 @@ export const SigninTotpCode = ({
|
|||
);
|
||||
|
||||
const formAttributes: FormAttributes = {
|
||||
inputFtlId: 'signin-totp-code-input-label-v3',
|
||||
inputLabelText: 'Enter code',
|
||||
inputFtlId: 'signin-totp-code-input-label-v4',
|
||||
inputLabelText: 'Enter 6-digit code',
|
||||
pattern: '[0-9]{6}',
|
||||
maxLength: 6,
|
||||
submitButtonFtlId: 'signin-totp-code-confirm-button',
|
||||
|
@ -142,18 +143,20 @@ export const SigninTotpCode = ({
|
|||
};
|
||||
|
||||
return (
|
||||
<AppLayout>
|
||||
<h2 className="font-bold text-xl text-left">
|
||||
<FtlMsg id="signin-totp-code-subheader">
|
||||
Enter your two-factor authentication security code (2FA)
|
||||
</FtlMsg>
|
||||
</h2>
|
||||
<AppLayout cardClass="card-base">
|
||||
<FtlMsg id="signin-totp-code-header">
|
||||
<HeadingPrimary>Sign in</HeadingPrimary>
|
||||
</FtlMsg>
|
||||
<FtlMsg id="signin-totp-code-subheader-v2">
|
||||
<h2 className="card-header">Enter two-step authentication code</h2>
|
||||
</FtlMsg>
|
||||
|
||||
<div className="flex space-x-4">
|
||||
<img src={protectionShieldIcon} alt="" />
|
||||
<FtlMsg id="signin-totp-code-instruction-v3">
|
||||
<p id="totp-code-instruction" className="my-5 text-md text-left">
|
||||
Check your authenticator app to confirm your sign-in.
|
||||
<FtlMsg id="signin-totp-code-instruction-v4">
|
||||
<p className="my-5 text-md">
|
||||
Check your <strong>authenticator app</strong> to confirm your
|
||||
sign-in.
|
||||
</p>
|
||||
</FtlMsg>
|
||||
</div>
|
||||
|
@ -172,7 +175,7 @@ export const SigninTotpCode = ({
|
|||
setCodeErrorMessage,
|
||||
}}
|
||||
/>
|
||||
<div className="mt-5 link-blue text-sm flex justify-between">
|
||||
<div className="mt-10 link-blue text-sm flex justify-between">
|
||||
<FtlMsg id="signin-totp-code-other-account-link">
|
||||
{/* TODO in FXA-8636 replace with Link component once index reactified */}
|
||||
<a
|
||||
|
|
Загрузка…
Ссылка в новой задаче