feat: update logistration pages (#591)

- removed few unused classes
- updated login page to rely on error messages generated
from the frontend only.

VAN-138
This commit is contained in:
Zainab Amir
2022-06-30 17:02:04 +05:00
committed by GitHub
parent f066880c7c
commit 5f2570c440
10 changed files with 29 additions and 101 deletions

View File

@@ -591,11 +591,6 @@ select.form-control {
border: 2px solid #F0CC00;
}
.one-rem-font {
font-size: 0.99rem;
color: #707070;
}
.institute-heading {
color: $primary-700;
}
@@ -668,16 +663,13 @@ select.form-control {
}
}
.arrow-back-icon {
margin-top:2px;
}
.icon-size {
width: 2.3rem;
}
.has-floating-label {
color: $gray-500;
}
.pgn__form-control-floating-label .pgn__form-control-floating-label-content {
font-size: 0.875rem;
line-height: 1.5;

View File

@@ -1,17 +1,8 @@
// Utility functions
import * as QueryString from 'query-string';
import { AUTH_PARAMS } from '../constants';
export default function processLink(link) {
let matches;
link.replace(/(.*?)<a href=["']([^"']*).*?>([^<]+)<\/a>(.*)/g, function () { // eslint-disable-line func-names
matches = Array.prototype.slice.call(arguments, 1, 5); // eslint-disable-line prefer-rest-params
});
return matches;
}
export const getTpaProvider = (tpaHintProvider, primaryProviders, secondaryProviders) => {
let tpaProvider = null;
let skipHintedLogin = false;

View File

@@ -1,18 +1,5 @@
import { LOGIN_PAGE } from '../constants';
import processLink, { updatePathWithQueryParams } from './dataUtils';
describe('processLink', () => {
it('should use the provided processLink function to', () => {
const expectedHref = 'http://test.server.com/';
const expectedText = 'test link';
const link = `<a href="${expectedHref}">${expectedText}</a>`;
const matches = processLink(link);
expect(matches[1]).toEqual(expectedHref);
expect(matches[2]).toEqual(expectedText);
});
});
import { updatePathWithQueryParams } from './dataUtils';
describe('updatePathWithQueryParams', () => {
it('should append query params into the path', () => {

View File

@@ -1,5 +1,4 @@
export {
default,
getTpaProvider,
getTpaHint,
updatePathWithQueryParams,

View File

@@ -31,10 +31,11 @@ const ForgotPasswordPage = (props) => {
const { intl, status, submitState } = props;
const platformName = getConfig().SITE_NAME;
const supportUrl = getConfig().LOGIN_ISSUE_SUPPORT_LINK;
const regex = new RegExp(VALID_EMAIL_REGEX, 'i');
const [validationError, setValidationError] = useState('');
const [key, setKey] = useState('');
const supportUrl = getConfig().LOGIN_ISSUE_SUPPORT_LINK;
useEffect(() => {
sendPageEvent('login_and_registration', 'reset');
@@ -55,8 +56,8 @@ const ForgotPasswordPage = (props) => {
};
const tabTitle = (
<div className="d-flex">
<Icon src={ChevronLeft} className="arrow-back-icon" />
<div className="d-inline-flex flex-wrap align-items-center">
<Icon src={ChevronLeft} />
<span className="ml-2">{intl.formatMessage(messages['sign.in.text'])}</span>
</div>
);
@@ -64,7 +65,7 @@ const ForgotPasswordPage = (props) => {
return (
<BaseComponent>
<div>
<Tabs activeKey="" id="controlled-tab-example" onSelect={(k) => setKey(k)}>
<Tabs activeKey="" id="controlled-tab" onSelect={(k) => setKey(k)}>
<Tab title={tabTitle} eventKey={LOGIN_PAGE} />
</Tabs>
{ key && (
@@ -132,14 +133,16 @@ const ForgotPasswordPage = (props) => {
name="forgot-password"
className="ml-4 font-weight-500 text-body"
destination={supportUrl}
onClick={e => {
e.preventDefault();
window.open(supportUrl, '_blank');
}}
>{intl.formatMessage(messages['need.help.sign.in.text'])}
target="_blank"
showLaunchIcon={false}
>
{intl.formatMessage(messages['need.help.sign.in.text'])}
</Hyperlink>
<p className="mt-5 one-rem-font">{intl.formatMessage(messages['additional.help.text'])}
<span><Hyperlink isInline destination={`mailto:${getConfig().INFO_EMAIL}`}>{getConfig().INFO_EMAIL}</Hyperlink></span>
<p className="mt-5 small text-gray-700">
{intl.formatMessage(messages['additional.help.text'], { platformName })}
<span>
<Hyperlink isInline destination={`mailto:${getConfig().INFO_EMAIL}`}>{getConfig().INFO_EMAIL}</Hyperlink>
</span>
</p>
</Form>
</>

View File

@@ -84,7 +84,7 @@ const messages = defineMessages({
},
'additional.help.text': {
id: 'additional.help.text',
defaultMessage: 'For additional help, contact edX support at ',
defaultMessage: 'For additional help, contact {platformName} support at ',
description: 'additional help text on forgot password page',
},
'sign.in.text': {

View File

@@ -6,7 +6,6 @@ import { Alert, Hyperlink } from '@edx/paragon';
import { Error } from '@edx/paragon/icons';
import PropTypes from 'prop-types';
import processLink from '../data/utils';
import ChangePasswordPrompt from './ChangePasswordPrompt';
import {
ACCOUNT_LOCKED_OUT,
@@ -24,10 +23,9 @@ import messages from './messages';
const LoginFailureMessage = (props) => {
const { intl } = props;
const { context, errorCode, value } = props.loginError;
const { context, errorCode } = props.loginError;
const authService = getAuthService();
let errorList;
let link;
let resetLink = (
<Hyperlink destination="/reset" isInline>
{intl.formatMessage(messages['login.incorrect.credentials.error.reset.link.text'])}
@@ -70,9 +68,6 @@ const LoginFailureMessage = (props) => {
);
break;
}
case INTERNAL_SERVER_ERROR:
errorList = <p>{intl.formatMessage(messages['internal.server.error.message'])}</p>;
break;
case INVALID_FORM:
errorList = <p>{intl.formatMessage(messages['login.form.invalid.error.message'])}</p>;
break;
@@ -149,28 +144,10 @@ const LoginFailureMessage = (props) => {
);
case REQUIRE_PASSWORD_CHANGE:
return <ChangePasswordPrompt />;
case INTERNAL_SERVER_ERROR:
default:
// TODO: use errorCode instead of processing error messages on frontend
errorList = value.trim().split('\n');
errorList = errorList.map((error) => {
let matches;
if (error.includes('a href')) {
matches = processLink(error);
const [beforeLink, href, linkText, afterLink] = matches;
link = href;
if (href.indexOf('/dashboard?tpa_hint') === 0) {
link = `/login?next=${href}`;
}
return (
<p key={error}>
{beforeLink}
<a href={link}>{linkText}</a>
{afterLink}
</p>
);
}
return <p key={error}>{error}</p>;
});
errorList = <p>{intl.formatMessage(messages['internal.server.error.message'])}</p>;
break;
}
return (
@@ -185,7 +162,6 @@ LoginFailureMessage.defaultProps = {
loginError: {
redirectUrl: null,
errorCode: null,
value: '',
},
};
@@ -194,7 +170,6 @@ LoginFailureMessage.propTypes = {
context: PropTypes.object,
email: PropTypes.string,
errorCode: PropTypes.string,
value: PropTypes.string,
redirectUrl: PropTypes.string,
}),
intl: intlShape.isRequired,

View File

@@ -201,11 +201,10 @@ describe('LoginFailureMessage', () => {
expect(loginFailureMessage.find('#login-failure-alert').first().text()).toEqual(expectedMessage);
});
it('should match direct render of error message', () => {
const errorMessage = 'Email or password is incorrect.';
it('should match internal server of error message', () => {
props = {
loginError: {
value: errorMessage,
errorCode: 'invalid-error-code',
},
};
@@ -215,29 +214,10 @@ describe('LoginFailureMessage', () => {
</IntlProvider>,
);
const expectedMessage = 'We couldn\'t sign you in.'.concat(errorMessage);
const expectedMessage = 'We couldn\'t sign you in.An error has occurred. Try refreshing the page, or check your internet connection.';
expect(loginFailureMessage.find('#login-failure-alert').first().text()).toEqual(expectedMessage);
});
it('should match error message containing link snapshot', () => {
props = {
loginError: {
value: 'To be on the safe side, you can reset your password <a href="/reset">here</a> before you try again.\n',
},
};
const loginFailureMessage = mount(
<IntlProvider locale="en">
<IntlLoginFailureMessage {...props} />
</IntlProvider>,
);
const expectedMessage = 'We couldn\'t sign you in.To be on the safe side, you can reset your password here before you try again.';
expect(loginFailureMessage.find('#login-failure-alert').first().text()).toEqual(expectedMessage);
expect(loginFailureMessage.find('#login-failure-alert').find('a').props().href).toEqual('/reset');
});
it('should show modal that nudges users to change password', () => {
props = {
loginError: {

View File

@@ -13,6 +13,7 @@ import configureStore from 'redux-mock-store';
import { COMPLETE_STATE, PENDING_STATE } from '../../data/constants';
import { loginRequest, loginRequestFailure, loginRequestReset } from '../data/actions';
import { INTERNAL_SERVER_ERROR } from '../data/constants';
import LoginFailureMessage from '../LoginFailure';
import LoginPage from '../LoginPage';
@@ -201,12 +202,12 @@ describe('LoginPage', () => {
// ******** test alert messages ********
it('should match login error message', () => {
const errorMessage = 'Email or password is incorrect.';
const errorMessage = 'An error has occurred. Try refreshing the page, or check your internet connection.';
store = mockStore({
...initialState,
login: {
...initialState.login,
loginError: { value: errorMessage },
loginError: { errorCode: INTERNAL_SERVER_ERROR },
},
});

View File

@@ -138,8 +138,8 @@ const ResetPasswordPage = (props) => {
};
const tabTitle = (
<div className="d-flex">
<Icon src={ChevronLeft} className="arrow-back-icon" />
<div className="d-inline-flex flex-wrap align-items-center">
<Icon src={ChevronLeft} />
<span className="ml-2">{intl.formatMessage(messages['sign.in'])}</span>
</div>
);