Merge pull request #17658 from edx/MLoTurco/learner-3925-search
Add Search component to entitlement support app
This commit is contained in:
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -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',
|
||||
};
|
||||
|
||||
@@ -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,
|
||||
};
|
||||
@@ -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,
|
||||
};
|
||||
@@ -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,
|
||||
};
|
||||
|
||||
@@ -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;
|
||||
@@ -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;
|
||||
@@ -0,0 +1,8 @@
|
||||
import { combineReducers } from 'redux';
|
||||
|
||||
import entitlements from './entitlements';
|
||||
import error from './error';
|
||||
|
||||
const rootReducer = combineReducers({ entitlements, error });
|
||||
|
||||
export default rootReducer;
|
||||
@@ -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;
|
||||
@@ -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>
|
||||
);
|
||||
|
||||
@@ -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
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
@@ -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",
|
||||
|
||||
Reference in New Issue
Block a user