diff --git a/src/forgot-password/data/tests/sagas.test.js b/src/forgot-password/data/tests/sagas.test.js
index 3f2a8704..e523fc4d 100644
--- a/src/forgot-password/data/tests/sagas.test.js
+++ b/src/forgot-password/data/tests/sagas.test.js
@@ -3,6 +3,9 @@ import { runSaga } from 'redux-saga';
import * as actions from '../actions';
import { handleForgotPassword } from '../sagas';
import * as api from '../service';
+import initializeMockLogging from '../../../setupTest';
+
+const { loggingService } = initializeMockLogging();
describe('handleForgotPassword', () => {
const params = {
@@ -13,6 +16,10 @@ describe('handleForgotPassword', () => {
},
};
+ beforeEach(() => {
+ loggingService.logError.mockReset();
+ });
+
it('should handle 500 error code', async () => {
const passwordErrorResponse = { response: { status: 500 } };
diff --git a/src/login/LoginFailure.jsx b/src/login/LoginFailure.jsx
index 28e587ef..9c41cdef 100644
--- a/src/login/LoginFailure.jsx
+++ b/src/login/LoginFailure.jsx
@@ -6,8 +6,11 @@ import PropTypes from 'prop-types';
import processLink from '../data/utils';
import {
+ ACCOUNT_LOCKED_OUT,
+ FAILED_LOGIN_ATTEMPT,
FORBIDDEN_REQUEST,
INACTIVE_USER,
+ INCORRECT_EMAIL_PASSWORD,
INTERNAL_SERVER_ERROR,
NON_COMPLIANT_PASSWORD_EXCEPTION,
} from './data/constants';
@@ -73,6 +76,62 @@ const LoginFailureMessage = (props) => {
);
break;
+ case FAILED_LOGIN_ATTEMPT: {
+ const resetLink = (
+
+ {intl.formatMessage(messages['login.failed.link.text'])}
+
+ );
+ errorList = (
+ <>
+
+ {intl.formatMessage(messages['login.incorrect.credentials.error'])}
+
+
+ {intl.formatMessage(messages['login.failed.attempt.error'], { remainingAttempts: context.remainingAttempts })}
+
+
+
+
+ >
+ );
+ break;
+ }
+ case ACCOUNT_LOCKED_OUT: {
+ const resetLink = (
+
+ {intl.formatMessage(messages['login.failed.link.text'])}
+
+ );
+ errorList = (
+ <>
+
+ {intl.formatMessage(messages['login.locked.out.error.message'], { lockedOutPeriod: context.lockedOutPeriod })}
+
+
+
+
+ >
+ );
+ break;
+ }
+ case INCORRECT_EMAIL_PASSWORD:
+ errorList = (
+
+ {intl.formatMessage(messages['login.incorrect.credentials.error'])}
+
+ );
+ break;
default:
// TODO: use errorCode instead of processing error messages on frontend
errorList = value.trim().split('\n');
@@ -110,7 +169,7 @@ LoginFailureMessage.defaultProps = {
LoginFailureMessage.propTypes = {
loginError: PropTypes.shape({
- context: PropTypes.objectOf(PropTypes.string),
+ context: PropTypes.object,
email: PropTypes.string,
errorCode: PropTypes.string,
value: PropTypes.string,
diff --git a/src/login/data/constants.js b/src/login/data/constants.js
index 6f5ff601..ce65c6fc 100644
--- a/src/login/data/constants.js
+++ b/src/login/data/constants.js
@@ -3,6 +3,9 @@ export const INACTIVE_USER = 'inactive-user';
export const INTERNAL_SERVER_ERROR = 'internal-server-error';
export const NON_COMPLIANT_PASSWORD_EXCEPTION = 'NonCompliantPasswordException';
export const FORBIDDEN_REQUEST = 'forbidden-request';
+export const FAILED_LOGIN_ATTEMPT = 'failed-login-attempt';
+export const ACCOUNT_LOCKED_OUT = 'account-locked-out';
+export const INCORRECT_EMAIL_PASSWORD = 'incorrect-email-or-password';
// Account Activation Message
export const ACCOUNT_ACTIVATION_MESSAGE = {
diff --git a/src/login/messages.jsx b/src/login/messages.jsx
index 23b6b08f..0099cca7 100644
--- a/src/login/messages.jsx
+++ b/src/login/messages.jsx
@@ -162,6 +162,26 @@ const messages = defineMessages({
defaultMessage: 'contact {platformName} Support',
description: 'Link text used in inactive user error message to go to learner help center',
},
+ 'login.failed.link.text': {
+ id: 'login.failed.link.text',
+ defaultMessage: 'here',
+ description: 'Link text used in failed login attempt user error message to reset password',
+ },
+ 'login.incorrect.credentials.error': {
+ id: 'login.incorrect.credentials.error',
+ defaultMessage: 'Email or password is incorrect.',
+ description: 'Error message for incorrect email or password',
+ },
+ 'login.failed.attempt.error': {
+ id: 'login.failed.attempt.error',
+ defaultMessage: 'You have {remainingAttempts} more sign-in attempts before your account is temporarily locked.',
+ description: 'Failed login attempts error message',
+ },
+ 'login.locked.out.error.message': {
+ id: 'login.locked.out.error.message',
+ defaultMessage: 'To protect your account, it’s been temporarily locked. Try again in {lockedOutPeriod} minutes.',
+ description: 'Account locked out user message',
+ },
});
export default messages;