diff --git a/lms/djangoapps/support/static/support/jsx/entitlements/components/Main/Main.jsx b/lms/djangoapps/support/static/support/jsx/entitlements/components/Main/Main.jsx
new file mode 100644
index 0000000000..3c09151fd2
--- /dev/null
+++ b/lms/djangoapps/support/static/support/jsx/entitlements/components/Main/Main.jsx
@@ -0,0 +1,27 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+
+import { StatusAlert } from '@edx/paragon';
+import SearchContainer from '../Search/SearchContainer.jsx';
+
+const Main = props => (
+
+
+
+ Entitlement Support Page
+
+
+
+);
+
+Main.propTypes = {
+ errorMessage: PropTypes.string.isRequired,
+ dismissErrorMessage: PropTypes.func.isRequired,
+};
+
+export default Main;
diff --git a/lms/djangoapps/support/static/support/jsx/entitlements/components/Main/MainContainer.jsx b/lms/djangoapps/support/static/support/jsx/entitlements/components/Main/MainContainer.jsx
new file mode 100644
index 0000000000..39c342b0a1
--- /dev/null
+++ b/lms/djangoapps/support/static/support/jsx/entitlements/components/Main/MainContainer.jsx
@@ -0,0 +1,20 @@
+import { connect } from 'react-redux';
+
+import { dismissError } from '../../data/actions/error';
+import Main from './Main.jsx';
+
+
+const mapStateToProps = state => ({
+ errorMessage: state.error,
+});
+
+const mapDispatchToProps = dispatch => ({
+ dismissErrorMessage: () => dispatch(dismissError()),
+});
+
+const MainContainer = connect(
+ mapStateToProps,
+ mapDispatchToProps,
+)(Main);
+
+export default MainContainer;
diff --git a/lms/djangoapps/support/static/support/jsx/entitlements/components/Search/Search.jsx b/lms/djangoapps/support/static/support/jsx/entitlements/components/Search/Search.jsx
new file mode 100644
index 0000000000..9cd62bc100
--- /dev/null
+++ b/lms/djangoapps/support/static/support/jsx/entitlements/components/Search/Search.jsx
@@ -0,0 +1,47 @@
+import React from 'react';
+import { InputText } from '@edx/paragon';
+import PropTypes from 'prop-types';
+
+
+class Search extends React.Component {
+ constructor(props) {
+ super(props);
+ this.state = { username: '' };
+
+ this.handleSubmit = this.handleSubmit.bind(this);
+ this.handleUsernameChange = this.handleUsernameChange.bind(this);
+ }
+
+ handleSubmit(event) {
+ event.preventDefault();
+ // updating state will cause react to re-render dom, the default refresh is unneeded
+ this.props.fetchEntitlements(this.state.username);
+ }
+
+ handleUsernameChange(username) {
+ this.setState({ username });
+ }
+
+ render() {
+ return (
+
+ );
+ }
+}
+
+Search.propTypes = {
+ fetchEntitlements: PropTypes.func.isRequired,
+};
+
+export default Search;
diff --git a/lms/djangoapps/support/static/support/jsx/entitlements/components/Search/SearchContainer.jsx b/lms/djangoapps/support/static/support/jsx/entitlements/components/Search/SearchContainer.jsx
new file mode 100644
index 0000000000..80bdd3b240
--- /dev/null
+++ b/lms/djangoapps/support/static/support/jsx/entitlements/components/Search/SearchContainer.jsx
@@ -0,0 +1,20 @@
+import { connect } from 'react-redux';
+
+import { fetchEntitlements } from '../../data/actions/entitlement';
+import Search from './Search.jsx';
+
+const mapStateToProps = state => ({
+ entitlements: state.entitlements,
+});
+
+
+const mapDispatchToProps = dispatch => ({
+ fetchEntitlements: username => dispatch(fetchEntitlements(username)),
+});
+
+const SearchContainer = connect(
+ mapStateToProps,
+ mapDispatchToProps,
+)(Search);
+
+export default SearchContainer;
diff --git a/lms/djangoapps/support/static/support/jsx/entitlements/data/actions/constants.js b/lms/djangoapps/support/static/support/jsx/entitlements/data/actions/constants.js
new file mode 100644
index 0000000000..07b700bda0
--- /dev/null
+++ b/lms/djangoapps/support/static/support/jsx/entitlements/data/actions/constants.js
@@ -0,0 +1,12 @@
+export const entitlementActions = {
+ fetch: {
+ SUCCESS: 'FETCH_ENTITLEMENTS_SUCCESS',
+ FAILURE: 'FETCH_ENTITLEMENTS_FAILURE',
+ },
+};
+
+export const errorActions = {
+ DISPLAY_ERROR: 'DISPLAY_ERROR',
+ DISMISS_ERROR: 'DISMISS_ERROR',
+};
+
diff --git a/lms/djangoapps/support/static/support/jsx/entitlements/data/actions/entitlement.js b/lms/djangoapps/support/static/support/jsx/entitlements/data/actions/entitlement.js
new file mode 100644
index 0000000000..e87397beac
--- /dev/null
+++ b/lms/djangoapps/support/static/support/jsx/entitlements/data/actions/entitlement.js
@@ -0,0 +1,35 @@
+import { getEntitlements } from '../api/client';
+
+import { entitlementActions } from './constants';
+import { displayError } from './error';
+
+const fetchEntitlementsSuccess = entitlements => ({
+ type: entitlementActions.fetch.SUCCESS,
+ entitlements,
+});
+
+const fetchEntitlementsFailure = error =>
+ dispatch =>
+ dispatch(displayError('Error Getting Entitlements', error));
+
+const fetchEntitlements = username =>
+ (dispatch) => {
+ getEntitlements(username)
+ .then((response) => {
+ if (response.ok) {
+ return response.json();
+ }
+ throw new Error(response);
+ })
+ .then(
+ json => dispatch(fetchEntitlementsSuccess(json.results)),
+ error => dispatch(fetchEntitlementsFailure(error)),
+ );
+ };
+
+
+export {
+ fetchEntitlements,
+ fetchEntitlementsSuccess,
+ fetchEntitlementsFailure,
+};
diff --git a/lms/djangoapps/support/static/support/jsx/entitlements/data/actions/error.js b/lms/djangoapps/support/static/support/jsx/entitlements/data/actions/error.js
new file mode 100644
index 0000000000..e859381ed8
--- /dev/null
+++ b/lms/djangoapps/support/static/support/jsx/entitlements/data/actions/error.js
@@ -0,0 +1,15 @@
+import { errorActions } from './constants';
+
+const displayError = (message, error) => ({
+ type: errorActions.DISPLAY_ERROR,
+ error: `${message}: ${error}`,
+});
+
+const dismissError = () => ({
+ type: errorActions.DISMISS_ERROR,
+});
+
+export {
+ displayError,
+ dismissError,
+};
diff --git a/lms/djangoapps/support/static/support/jsx/entitlements/data/api/client.js b/lms/djangoapps/support/static/support/jsx/entitlements/data/api/client.js
index 4271011dae..807edec4e9 100644
--- a/lms/djangoapps/support/static/support/jsx/entitlements/data/api/client.js
+++ b/lms/djangoapps/support/static/support/jsx/entitlements/data/api/client.js
@@ -9,7 +9,7 @@ const HEADERS = {
'X-CSRFToken': Cookies.get('csrftoken'),
};
-const requestEntitlements = ({ username }) => fetch(
+const getEntitlements = username => fetch(
`${entitlementApi}/?user=${username}`, {
credentials: 'same-origin',
method: 'get',
@@ -54,7 +54,7 @@ const updateEntitlement = ({ entitlementUuid, unenrolledRun, action, comments })
export {
- requestEntitlements,
+ getEntitlements,
createEntitlement,
updateEntitlement,
};
diff --git a/lms/djangoapps/support/static/support/jsx/entitlements/data/reducers/entitlements.js b/lms/djangoapps/support/static/support/jsx/entitlements/data/reducers/entitlements.js
new file mode 100644
index 0000000000..1707dcf3bd
--- /dev/null
+++ b/lms/djangoapps/support/static/support/jsx/entitlements/data/reducers/entitlements.js
@@ -0,0 +1,12 @@
+import { entitlementActions } from '../actions/constants';
+
+const entitlements = (state = [], action) => {
+ switch (action.type) {
+ case entitlementActions.fetch.SUCCESS:
+ return action.entitlements;
+ default:
+ return state;
+ }
+};
+
+export default entitlements;
diff --git a/lms/djangoapps/support/static/support/jsx/entitlements/data/reducers/error.js b/lms/djangoapps/support/static/support/jsx/entitlements/data/reducers/error.js
new file mode 100644
index 0000000000..f640f3ed94
--- /dev/null
+++ b/lms/djangoapps/support/static/support/jsx/entitlements/data/reducers/error.js
@@ -0,0 +1,15 @@
+import { errorActions, entitlementActions } from '../actions/constants';
+
+const error = (state = '', action) => {
+ switch (action.type) {
+ case errorActions.DISPLAY_ERROR:
+ return action.error;
+ case errorActions.DISMISS_ERROR:
+ case entitlementActions.fetch.SUCCESS:
+ return '';
+ default:
+ return state;
+ }
+};
+
+export default error;
diff --git a/lms/djangoapps/support/static/support/jsx/entitlements/data/reducers/index.js b/lms/djangoapps/support/static/support/jsx/entitlements/data/reducers/index.js
new file mode 100644
index 0000000000..71f1ad1bed
--- /dev/null
+++ b/lms/djangoapps/support/static/support/jsx/entitlements/data/reducers/index.js
@@ -0,0 +1,8 @@
+import { combineReducers } from 'redux';
+
+import entitlements from './entitlements';
+import error from './error';
+
+const rootReducer = combineReducers({ entitlements, error });
+
+export default rootReducer;
diff --git a/lms/djangoapps/support/static/support/jsx/entitlements/data/store.js b/lms/djangoapps/support/static/support/jsx/entitlements/data/store.js
new file mode 100644
index 0000000000..15d64ddb30
--- /dev/null
+++ b/lms/djangoapps/support/static/support/jsx/entitlements/data/store.js
@@ -0,0 +1,21 @@
+import { createStore, applyMiddleware } from 'redux';
+import thunkMiddleware from 'redux-thunk';
+
+import rootReducer from './reducers/index';
+
+const defaultState = {
+ entitlements: [],
+ error: '',
+};
+
+const configureStore = initialState =>
+ createStore(
+ rootReducer,
+ initialState,
+ applyMiddleware(thunkMiddleware),
+ );
+
+
+const store = configureStore(defaultState);
+
+export default store;
diff --git a/lms/djangoapps/support/static/support/jsx/entitlements/index.jsx b/lms/djangoapps/support/static/support/jsx/entitlements/index.jsx
index ce5b7487cc..a024373726 100644
--- a/lms/djangoapps/support/static/support/jsx/entitlements/index.jsx
+++ b/lms/djangoapps/support/static/support/jsx/entitlements/index.jsx
@@ -1,9 +1,12 @@
import React from 'react';
-const EntitlementSupportPage = () => (
-
- Base Entitlement Support Page
-
-);
+import { Provider } from 'react-redux';
+import store from './data/store';
-export default EntitlementSupportPage;
+import MainContainer from './components/Main/MainContainer.jsx';
+
+export const EntitlementSupportPage = props => (
+
+
+
+);
diff --git a/lms/templates/support/entitlement.html b/lms/templates/support/entitlement.html
index f193160f4c..71c03d930d 100644
--- a/lms/templates/support/entitlement.html
+++ b/lms/templates/support/entitlement.html
@@ -26,7 +26,7 @@ from openedx.core.djangolib.js_utils import js_escaped_string
id="entitlement-support-page",
props={
'ecommerceUrl': ecommerce_url,
- 'supportReasons': support_actions
+ 'supportActions': support_actions
}
)
}
diff --git a/package.json b/package.json
index e2ea065c90..3dcc15c0f9 100644
--- a/package.json
+++ b/package.json
@@ -42,7 +42,10 @@
"raw-loader": "0.5.1",
"react": "16.1.0",
"react-dom": "16.1.0",
+ "react-redux": "5.0.7",
"react-slick": "0.16.0",
+ "redux": "3.7.2",
+ "redux-thunk": "2.2.0",
"requirejs": "2.3.5",
"rtlcss": "2.2.1",
"sass-loader": "6.0.6",