refactor: remove legacy code and move redesign code to src
VAN-670
This commit is contained in:
33
src/data/configureStore.js
Normal file
33
src/data/configureStore.js
Normal file
@@ -0,0 +1,33 @@
|
||||
import { getConfig } from '@edx/frontend-platform';
|
||||
import { applyMiddleware, createStore, compose } from 'redux';
|
||||
import thunkMiddleware from 'redux-thunk';
|
||||
import { composeWithDevTools } from 'redux-devtools-extension';
|
||||
import { createLogger } from 'redux-logger';
|
||||
import createSagaMiddleware from 'redux-saga';
|
||||
|
||||
import createRootReducer from './reducers';
|
||||
import rootSaga from './sagas';
|
||||
|
||||
const sagaMiddleware = createSagaMiddleware();
|
||||
|
||||
function composeMiddleware() {
|
||||
if (getConfig().ENVIRONMENT === 'development') {
|
||||
const loggerMiddleware = createLogger({
|
||||
collapsed: true,
|
||||
});
|
||||
return composeWithDevTools(applyMiddleware(thunkMiddleware, sagaMiddleware, loggerMiddleware));
|
||||
}
|
||||
|
||||
return compose(applyMiddleware(thunkMiddleware, sagaMiddleware));
|
||||
}
|
||||
|
||||
export default function configureStore(initialState = {}) {
|
||||
const store = createStore(
|
||||
createRootReducer(),
|
||||
initialState,
|
||||
composeMiddleware(),
|
||||
);
|
||||
sagaMiddleware.run(rootSaga);
|
||||
|
||||
return store;
|
||||
}
|
||||
33
src/data/constants.js
Normal file
33
src/data/constants.js
Normal file
@@ -0,0 +1,33 @@
|
||||
// URL Paths
|
||||
export const LOGIN_PAGE = '/login';
|
||||
export const REGISTER_PAGE = '/register';
|
||||
export const RESET_PAGE = '/reset';
|
||||
export const WELCOME_PAGE = '/welcome';
|
||||
export const DEFAULT_REDIRECT_URL = '/dashboard';
|
||||
export const PASSWORD_RESET_CONFIRM = '/password_reset_confirm/:token/';
|
||||
export const PAGE_NOT_FOUND = '/notfound';
|
||||
export const ENTERPRISE_LOGIN_URL = '/enterprise/login';
|
||||
|
||||
// Constants
|
||||
export const SUPPORTED_ICON_CLASSES = ['apple', 'facebook', 'google', 'microsoft'];
|
||||
|
||||
// Error Codes
|
||||
export const INTERNAL_SERVER_ERROR = 'internal-server-error';
|
||||
export const API_RATELIMIT_ERROR = 'api-ratelimit-error';
|
||||
|
||||
// States
|
||||
export const DEFAULT_STATE = 'default';
|
||||
export const PENDING_STATE = 'pending';
|
||||
export const COMPLETE_STATE = 'complete';
|
||||
|
||||
// Regex
|
||||
export const VALID_EMAIL_REGEX = '(^[-!#$%&\'*+/=?^_`{}|~0-9A-Z]+(\\.[-!#$%&\'*+/=?^_`{}|~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}\\]$';
|
||||
export const LETTER_REGEX = /[a-zA-Z]/;
|
||||
export const NUMBER_REGEX = /\d/;
|
||||
|
||||
// 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'];
|
||||
37
src/data/reducers.js
Executable file
37
src/data/reducers.js
Executable file
@@ -0,0 +1,37 @@
|
||||
import { combineReducers } from 'redux';
|
||||
|
||||
import {
|
||||
reducer as loginReducer,
|
||||
storeName as loginStoreName,
|
||||
} from '../login';
|
||||
import {
|
||||
reducer as registerReducer,
|
||||
storeName as registerStoreName,
|
||||
} from '../register';
|
||||
import {
|
||||
reducer as commonComponentsReducer,
|
||||
storeName as commonComponentsStoreName,
|
||||
} from '../common-components';
|
||||
import {
|
||||
reducer as forgotPasswordReducer,
|
||||
storeName as forgotPasswordStoreName,
|
||||
} from '../forgot-password';
|
||||
import {
|
||||
reducer as resetPasswordReducer,
|
||||
storeName as resetPasswordStoreName,
|
||||
} from '../reset-password';
|
||||
|
||||
import {
|
||||
reducer as welcomePageReducers,
|
||||
storeName as welcomePageStoreName,
|
||||
} from '../welcome';
|
||||
|
||||
const createRootReducer = () => combineReducers({
|
||||
[loginStoreName]: loginReducer,
|
||||
[registerStoreName]: registerReducer,
|
||||
[commonComponentsStoreName]: commonComponentsReducer,
|
||||
[forgotPasswordStoreName]: forgotPasswordReducer,
|
||||
[resetPasswordStoreName]: resetPasswordReducer,
|
||||
[welcomePageStoreName]: welcomePageReducers,
|
||||
});
|
||||
export default createRootReducer;
|
||||
19
src/data/sagas.js
Normal file
19
src/data/sagas.js
Normal file
@@ -0,0 +1,19 @@
|
||||
import { all } from 'redux-saga/effects';
|
||||
|
||||
import { saga as registrationSaga } from '../register';
|
||||
import { saga as loginSaga } from '../login';
|
||||
import { saga as commonComponentsSaga } from '../common-components';
|
||||
import { saga as forgotPasswordSaga } from '../forgot-password';
|
||||
import { saga as resetPasswordSaga } from '../reset-password';
|
||||
import { saga as welcomePageSaga } from '../welcome';
|
||||
|
||||
export default function* rootSaga() {
|
||||
yield all([
|
||||
loginSaga(),
|
||||
registrationSaga(),
|
||||
commonComponentsSaga(),
|
||||
forgotPasswordSaga(),
|
||||
resetPasswordSaga(),
|
||||
welcomePageSaga(),
|
||||
]);
|
||||
}
|
||||
21
src/data/utils/cookies.js
Normal file
21
src/data/utils/cookies.js
Normal file
@@ -0,0 +1,21 @@
|
||||
import Cookies from 'universal-cookie';
|
||||
import { getConfig } from '@edx/frontend-platform';
|
||||
|
||||
export function setCookie(cookieName, cookieValue, cookieExpiry) {
|
||||
const cookies = new Cookies();
|
||||
const options = { domain: getConfig().COOKIE_DOMAIN, path: '/' };
|
||||
if (cookieExpiry) {
|
||||
options.expires = cookieExpiry;
|
||||
}
|
||||
cookies.set(cookieName, cookieValue, options);
|
||||
}
|
||||
|
||||
export default function setSurveyCookie(surveyType) {
|
||||
const cookieName = getConfig().USER_SURVEY_COOKIE_NAME;
|
||||
if (cookieName) {
|
||||
const signupTimestamp = (new Date()).getTime();
|
||||
// set expiry to exactly 24 hours from now
|
||||
const cookieExpiry = new Date(signupTimestamp + 1 * 864e5);
|
||||
setCookie(cookieName, surveyType, cookieExpiry);
|
||||
}
|
||||
}
|
||||
86
src/data/utils/dataUtils.js
Normal file
86
src/data/utils/dataUtils.js
Normal file
@@ -0,0 +1,86 @@
|
||||
// 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;
|
||||
[...primaryProviders, ...secondaryProviders].forEach((provider) => {
|
||||
if (provider.id === tpaHintProvider) {
|
||||
tpaProvider = provider;
|
||||
if (provider.skipHintedLogin) {
|
||||
skipHintedLogin = true;
|
||||
}
|
||||
}
|
||||
});
|
||||
return { provider: tpaProvider, skipHintedLogin };
|
||||
};
|
||||
|
||||
export const getTpaHint = () => {
|
||||
const params = QueryString.parse(window.location.search);
|
||||
let tpaHint = null;
|
||||
tpaHint = params.tpa_hint;
|
||||
if (!tpaHint) {
|
||||
const { next } = params;
|
||||
if (next) {
|
||||
const index = next.indexOf('tpa_hint=');
|
||||
if (index !== -1) {
|
||||
tpaHint = next.substring(index + 'tpa_hint='.length, next.length);
|
||||
}
|
||||
}
|
||||
}
|
||||
return tpaHint;
|
||||
};
|
||||
|
||||
export const updatePathWithQueryParams = (path) => {
|
||||
let queryParams = window.location.search;
|
||||
|
||||
if (!queryParams) {
|
||||
return path;
|
||||
}
|
||||
|
||||
if (queryParams.indexOf('track=pwreset') > -1) {
|
||||
queryParams = queryParams.replace(
|
||||
'?track=pwreset&', '?',
|
||||
).replace('?track=pwreset', '').replace('&track=pwreset', '').replace('?&', '?');
|
||||
}
|
||||
|
||||
return `${path}${queryParams}`;
|
||||
};
|
||||
|
||||
export const getAllPossibleQueryParam = () => {
|
||||
const urlParams = QueryString.parse(window.location.search);
|
||||
const params = {};
|
||||
Object.entries(urlParams).forEach(([key, value]) => {
|
||||
if (AUTH_PARAMS.indexOf(key) > -1) {
|
||||
params[key] = value;
|
||||
}
|
||||
});
|
||||
|
||||
return params;
|
||||
};
|
||||
|
||||
export const getActivationStatus = () => {
|
||||
const params = QueryString.parse(window.location.search);
|
||||
|
||||
return params.account_activation_status;
|
||||
};
|
||||
|
||||
export const isScrollBehaviorSupported = () => 'scrollBehavior' in document.documentElement.style;
|
||||
|
||||
export const windowScrollTo = (options) => {
|
||||
if (isScrollBehaviorSupported()) {
|
||||
return window.scrollTo(options);
|
||||
}
|
||||
|
||||
return window.scrollTo(options.top, options.left);
|
||||
};
|
||||
32
src/data/utils/dataUtils.test.js
Normal file
32
src/data/utils/dataUtils.test.js
Normal file
@@ -0,0 +1,32 @@
|
||||
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);
|
||||
});
|
||||
});
|
||||
|
||||
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);
|
||||
});
|
||||
});
|
||||
11
src/data/utils/index.js
Normal file
11
src/data/utils/index.js
Normal file
@@ -0,0 +1,11 @@
|
||||
export {
|
||||
default,
|
||||
getTpaProvider,
|
||||
getTpaHint,
|
||||
updatePathWithQueryParams,
|
||||
getAllPossibleQueryParam,
|
||||
getActivationStatus,
|
||||
windowScrollTo,
|
||||
} from './dataUtils';
|
||||
export { default as AsyncActionType } from './reduxUtils';
|
||||
export { default as setSurveyCookie, setCookie } from './cookies';
|
||||
34
src/data/utils/reduxUtils.js
Normal file
34
src/data/utils/reduxUtils.js
Normal file
@@ -0,0 +1,34 @@
|
||||
/**
|
||||
* Helper class to save time when writing out action types for asynchronous methods. Also helps
|
||||
* ensure that actions are namespaced.
|
||||
*/
|
||||
export default class AsyncActionType {
|
||||
constructor(topic, name) {
|
||||
this.topic = topic;
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
get BASE() {
|
||||
return `${this.topic}__${this.name}`;
|
||||
}
|
||||
|
||||
get BEGIN() {
|
||||
return `${this.topic}__${this.name}__BEGIN`;
|
||||
}
|
||||
|
||||
get SUCCESS() {
|
||||
return `${this.topic}__${this.name}__SUCCESS`;
|
||||
}
|
||||
|
||||
get FAILURE() {
|
||||
return `${this.topic}__${this.name}__FAILURE`;
|
||||
}
|
||||
|
||||
get RESET() {
|
||||
return `${this.topic}__${this.name}__RESET`;
|
||||
}
|
||||
|
||||
get FORBIDDEN() {
|
||||
return `${this.topic}__${this.name}__FORBIDDEN`;
|
||||
}
|
||||
}
|
||||
14
src/data/utils/reduxUtils.test.js
Normal file
14
src/data/utils/reduxUtils.test.js
Normal file
@@ -0,0 +1,14 @@
|
||||
import AsyncActionType from './reduxUtils';
|
||||
|
||||
describe('AsyncActionType', () => {
|
||||
it('should return well formatted action strings', () => {
|
||||
const actionType = new AsyncActionType('HOUSE_CATS', 'START_THE_RACE');
|
||||
|
||||
expect(actionType.BASE).toBe('HOUSE_CATS__START_THE_RACE');
|
||||
expect(actionType.BEGIN).toBe('HOUSE_CATS__START_THE_RACE__BEGIN');
|
||||
expect(actionType.SUCCESS).toBe('HOUSE_CATS__START_THE_RACE__SUCCESS');
|
||||
expect(actionType.FAILURE).toBe('HOUSE_CATS__START_THE_RACE__FAILURE');
|
||||
expect(actionType.RESET).toBe('HOUSE_CATS__START_THE_RACE__RESET');
|
||||
expect(actionType.FORBIDDEN).toBe('HOUSE_CATS__START_THE_RACE__FORBIDDEN');
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user