Skip to content

Commit

Permalink
Keep the query params intact within the app. (#201)
Browse files Browse the repository at this point in the history
Currently, if the user lands on one page with course_id and enroll action
params and navigates to another page with the MFE, the query params
are not passed to that other page and resulting in not enrolling into
the course.

Also add these query params into login and register payload.

VAN-415
  • Loading branch information
waheedahmed authored Mar 11, 2021
1 parent daae34d commit c2d9a93
Show file tree
Hide file tree
Showing 10 changed files with 105 additions and 39 deletions.
21 changes: 16 additions & 5 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

11 changes: 6 additions & 5 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -35,25 +35,27 @@
},
"dependencies": {
"@edx/brand": "npm:@edx/brand-openedx@1.1.0",
"@edx/frontend-component-cookie-policy-banner": "2.1.8",
"@edx/frontend-component-header": "2.2.4",
"@edx/frontend-platform": "1.8.4",
"@edx/frontend-component-cookie-policy-banner": "2.1.8",
"@edx/paragon": "13.16.1",
"@fortawesome/fontawesome-svg-core": "1.2.32",
"@fortawesome/free-brands-svg-icons": "5.15.1",
"@fortawesome/free-regular-svg-icons": "5.15.1",
"@fortawesome/free-solid-svg-icons": "5.15.1",
"@fortawesome/react-fontawesome": "0.1.13",
"core-js": "3.9.1",
"classnames": "2.2.6",
"core-js": "3.9.1",
"extract-react-intl-messages": "4.1.1",
"form-urlencoded": "4.2.1",
"formik": "2.2.6",
"lodash.camelcase": "4.3.0",
"lodash.snakecase": "4.1.1",
"prop-types": "15.7.2",
"query-string": "5.1.1",
"react": "16.14.0",
"react-dom": "16.14.0",
"react-helmet": "6.1.0",
"react-loading-skeleton": "2.1.1",
"react-redux": "7.2.2",
"react-router": "5.2.0",
Expand All @@ -64,9 +66,8 @@
"redux-mock-store": "1.5.4",
"redux-saga": "1.1.3",
"redux-thunk": "2.3.0",
"reselect": "4.0.0",
"react-helmet": "6.1.0",
"regenerator-runtime": "0.13.7"
"regenerator-runtime": "0.13.7",
"reselect": "4.0.0"
},
"devDependencies": {
"@edx/frontend-build": "5.6.8",
Expand Down
4 changes: 4 additions & 0 deletions src/data/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -24,3 +24,7 @@ export const VALID_EMAIL_REGEX = '(^[-!#$%&\'*+/=?^_`{}|~0-9A-Z]+(\\.[-!#$%&\'*+
+ '|^"([\\001-\\010\\013\\014\\016-\\037!#-\\[\\]-\\177]|\\\\[\\001-\\011\\013\\014\\016-\\177])*"'
+ ')@((?:[A-Z0-9](?:[A-Z0-9-]{0,61}[A-Z0-9])?\\.)+)(?:[A-Z0-9-]{2,63})'
+ '|\\[(25[0-5]|2[0-4]\\d|[0-1]?\\d?\\d)(\\.(25[0-5]|2[0-4]\\d|[0-1]?\\d?\\d)){3}\\]$';

// Query string parameters that can be passed to LMS to manage
// things like auto-enrollment upon login and registration.
export const AUTH_PARAMS = ['course_id', 'enrollment_action', 'course_mode', 'email_opt_in', 'purchase_workflow', 'next'];
25 changes: 25 additions & 0 deletions src/data/utils/dataUtils.js
Original file line number Diff line number Diff line change
@@ -1,5 +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
Expand Down Expand Up @@ -40,3 +43,25 @@ export const processTpaHintURL = (params) => {
}
return tpaHint;
};

export const updatePathWithQueryParams = (path) => {
const queryParams = window.location.search;

if (!queryParams) {
return path;
}

return `${path}${queryParams}`;
};

export const getAllPossibleQueryParam = () => {
const urlParams = QueryString.parse(document.location.search);
const params = {};
Object.entries(urlParams).forEach(([key, value]) => {
if (AUTH_PARAMS.indexOf(key) > -1) {
params[key] = value;
}
});

return params;
};
20 changes: 19 additions & 1 deletion src/data/utils/dataUtils.test.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
import processLink from './dataUtils';
import { LOGIN_PAGE } from '../constants';
import processLink, { updatePathWithQueryParams } from './dataUtils';

describe('processLink', () => {
it('should use the provided processLink function to', () => {
Expand All @@ -12,3 +13,20 @@ describe('processLink', () => {
expect(matches[2]).toEqual(expectedText);
});
});

describe('updatePathWithQueryParams', () => {
it('should append query params into the path', () => {
const params = '?course_id=testCourseId';
const expectedPath = `${LOGIN_PAGE}${params}`;

Object.defineProperty(window, 'location', {
value: {
href: 'http://localhost/',
search: params,
},
});
const updatedPath = updatePathWithQueryParams(LOGIN_PAGE);

expect(updatedPath).toEqual(expectedPath);
});
});
8 changes: 7 additions & 1 deletion src/data/utils/index.js
Original file line number Diff line number Diff line change
@@ -1,2 +1,8 @@
export { default, getTpaProvider, processTpaHintURL } from './dataUtils';
export {
default,
getTpaProvider,
processTpaHintURL,
updatePathWithQueryParams,
getAllPossibleQueryParam,
} from './dataUtils';
export { default as AsyncActionType } from './reduxUtils';
3 changes: 2 additions & 1 deletion src/forgot-password/ForgotPasswordPage.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ import {
import APIFailureMessage from '../common-components/APIFailureMessage';
import { INTERNAL_SERVER_ERROR, LOGIN_PAGE, VALID_EMAIL_REGEX } from '../data/constants';
import LoginHelpLinks from '../login/LoginHelpLinks';
import { updatePathWithQueryParams } from '../data/utils';

const ForgotPasswordPage = (props) => {
const { intl, status } = props;
Expand Down Expand Up @@ -92,7 +93,7 @@ const ForgotPasswordPage = (props) => {
{ siteName: getConfig().SITE_NAME })}
</title>
</Helmet>
{status === 'complete' ? <Redirect to={LOGIN_PAGE} /> : null}
{status === 'complete' ? <Redirect to={updatePathWithQueryParams(LOGIN_PAGE)} /> : null}
<div className="d-flex justify-content-center m-4">
<div className="d-flex flex-column">
<Form className="mw-500">
Expand Down
5 changes: 3 additions & 2 deletions src/login/LoginHelpLinks.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import {
RESET_PAGE,
} from '../data/constants';
import messages from './messages';
import { updatePathWithQueryParams } from '../data/utils';

const LoginHelpLinks = (props) => {
const { intl, page } = props;
Expand All @@ -31,15 +32,15 @@ const LoginHelpLinks = (props) => {
const forgotPasswordLink = () => (
<Hyperlink
className="field-link"
destination={RESET_PAGE}
destination={updatePathWithQueryParams(RESET_PAGE)}
onClick={handleForgotPasswordLinkClickEvent}
>
{intl.formatMessage(messages['forgot.password.link'])}
</Hyperlink>
);

const signUpLink = () => (
<Hyperlink className="field-link" destination={REGISTER_PAGE}>
<Hyperlink className="field-link" destination={updatePathWithQueryParams(REGISTER_PAGE)}>
{intl.formatMessage(messages['register.link'])}
</Hyperlink>
);
Expand Down
24 changes: 12 additions & 12 deletions src/login/LoginPage.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -32,7 +32,9 @@ import {
DEFAULT_REDIRECT_URL, DEFAULT_STATE, LOGIN_PAGE, REGISTER_PAGE, ENTERPRISE_LOGIN_URL, PENDING_STATE,
} from '../data/constants';
import { forgotPasswordResultSelector } from '../forgot-password';
import { getTpaProvider, processTpaHintURL } from '../data/utils';
import {
getTpaProvider, processTpaHintURL, updatePathWithQueryParams, getAllPossibleQueryParam,
} from '../data/utils';

class LoginPage extends React.Component {
constructor(props, context) {
Expand Down Expand Up @@ -90,16 +92,10 @@ class LoginPage extends React.Component {
return;
}

const params = (new URL(document.location)).searchParams;
const payload = { email, password };
const next = params.get('next');
const courseId = params.get('course_id');
if (next) {
payload.next = next;
}
if (courseId) {
payload.course_id = courseId;
}
let payload = { email, password };
const postParams = getAllPossibleQueryParam();

payload = { ...payload, ...postParams };
this.props.loginRequest(payload);
}

Expand Down Expand Up @@ -203,7 +199,11 @@ class LoginPage extends React.Component {
) : null}
<p>
{intl.formatMessage(messages['first.time.here'])}
<Hyperlink className="ml-1" destination={REGISTER_PAGE} onClick={this.handleCreateAccountLinkClickEvent}>
<Hyperlink
className="ml-1"
destination={updatePathWithQueryParams(REGISTER_PAGE)}
onClick={this.handleCreateAccountLinkClickEvent}
>
{intl.formatMessage(messages['create.an.account'])}.
</Hyperlink>
</p>
Expand Down
23 changes: 11 additions & 12 deletions src/register/RegistrationPage.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,9 @@ import EnterpriseSSO from '../common-components/EnterpriseSSO';
import {
DEFAULT_REDIRECT_URL, DEFAULT_STATE, LOGIN_PAGE, PENDING_STATE, REGISTER_PAGE,
} from '../data/constants';
import { getTpaProvider, processTpaHintURL } from '../data/utils';
import {
getTpaProvider, processTpaHintURL, updatePathWithQueryParams, getAllPossibleQueryParam,
} from '../data/utils';

class RegistrationPage extends React.Component {
constructor(props, context) {
Expand Down Expand Up @@ -153,8 +155,7 @@ class RegistrationPage extends React.Component {

handleSubmit = (e) => {
e.preventDefault();
const params = (new URL(document.location)).searchParams;
const payload = {
let payload = {
name: this.state.name,
username: this.state.username,
email: this.state.email,
Expand All @@ -168,14 +169,8 @@ class RegistrationPage extends React.Component {
payload.password = this.state.password;
}

const next = params.get('next');
const courseId = params.get('course_id');
if (next) {
payload.next = next;
}
if (courseId) {
payload.course_id = courseId;
}
const postParams = getAllPossibleQueryParam();
payload = { ...payload, ...postParams };

let finalValidation = this.state.formValid;
if (!this.state.formValid) {
Expand Down Expand Up @@ -461,7 +456,11 @@ class RegistrationPage extends React.Component {
)}
<p>
{intl.formatMessage(messages['already.have.an.edx.account'])}
<Hyperlink className="ml-1" destination={LOGIN_PAGE} onClick={this.handleLoginLinkClickEvent}>
<Hyperlink
className="ml-1"
destination={updatePathWithQueryParams(LOGIN_PAGE)}
onClick={this.handleLoginLinkClickEvent}
>
{intl.formatMessage(messages['sign.in.hyperlink'])}
</Hyperlink>
</p>
Expand Down

0 comments on commit c2d9a93

Please sign in to comment.