Merge pull request #17658 from edx/MLoTurco/learner-3925-search

Add Search component to entitlement support app
This commit is contained in:
Michael LoTurco
2018-03-13 12:21:29 -04:00
committed by GitHub
15 changed files with 247 additions and 9 deletions

View File

@@ -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 => (
<div>
<StatusAlert
alertType="danger"
dialog={props.errorMessage}
onClose={props.dismissErrorMessage}
open={!!props.errorMessage}
/>
<h2>
Entitlement Support Page
</h2>
<SearchContainer />
</div>
);
Main.propTypes = {
errorMessage: PropTypes.string.isRequired,
dismissErrorMessage: PropTypes.func.isRequired,
};
export default Main;

View File

@@ -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;

View File

@@ -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 (
<form onSubmit={this.handleSubmit}>
<InputText
name="username"
label="Search by Username"
value={this.state.username}
onChange={this.handleUsernameChange}
/>
<input
type="submit"
hidden
/>
</form>
);
}
}
Search.propTypes = {
fetchEntitlements: PropTypes.func.isRequired,
};
export default Search;

View File

@@ -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;

View File

@@ -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',
};

View File

@@ -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,
};

View File

@@ -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,
};

View File

@@ -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,
};

View File

@@ -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;

View File

@@ -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;

View File

@@ -0,0 +1,8 @@
import { combineReducers } from 'redux';
import entitlements from './entitlements';
import error from './error';
const rootReducer = combineReducers({ entitlements, error });
export default rootReducer;

View File

@@ -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;

View File

@@ -1,9 +1,12 @@
import React from 'react';
const EntitlementSupportPage = () => (
<div>
Base Entitlement Support Page
</div>
);
import { Provider } from 'react-redux';
import store from './data/store';
export default EntitlementSupportPage;
import MainContainer from './components/Main/MainContainer.jsx';
export const EntitlementSupportPage = props => (
<Provider store={store}>
<MainContainer {...props} />
</Provider>
);

View File

@@ -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
}
)
}

View File

@@ -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",