diff --git a/.babelrc b/.babelrc
index 20a87235f4..c844f15918 100644
--- a/.babelrc
+++ b/.babelrc
@@ -1,6 +1,7 @@
{
"plugins": [
- "transform-object-assign"
+ "transform-object-assign",
+ "transform-object-rest-spread"
],
"presets": [
[
diff --git a/lms/djangoapps/support/static/support/jsx/entitlements/components/EntitlementForm/container.jsx b/lms/djangoapps/support/static/support/jsx/entitlements/components/EntitlementForm/container.jsx
new file mode 100644
index 0000000000..5063648066
--- /dev/null
+++ b/lms/djangoapps/support/static/support/jsx/entitlements/components/EntitlementForm/container.jsx
@@ -0,0 +1,27 @@
+import { connect } from 'react-redux';
+
+import { createEntitlement, reissueEntitlement } from '../../data/actions/entitlement';
+import { closeForm } from '../../data/actions/form';
+
+import EntitlementForm from './index.jsx';
+
+const mapStateToProps = state => ({
+ formType: state.form.formType,
+ isOpen: state.form.isOpen,
+ entitlement: state.form.activeEntitlement,
+});
+
+const mapDispatchToProps = dispatch => ({
+ createEntitlement: ({ username, courseUuid, mode, comments }) =>
+ dispatch(createEntitlement({ username, courseUuid, mode, comments })),
+ reissueEntitlement: ({ entitlement, comments }) =>
+ dispatch(reissueEntitlement({ entitlement, comments })),
+ closeForm: () => dispatch(closeForm()),
+});
+
+const EntitlementFormContainer = connect(
+ mapStateToProps,
+ mapDispatchToProps,
+)(EntitlementForm);
+
+export default EntitlementFormContainer;
diff --git a/lms/djangoapps/support/static/support/jsx/entitlements/components/EntitlementForm/index.jsx b/lms/djangoapps/support/static/support/jsx/entitlements/components/EntitlementForm/index.jsx
new file mode 100644
index 0000000000..7bba4c712c
--- /dev/null
+++ b/lms/djangoapps/support/static/support/jsx/entitlements/components/EntitlementForm/index.jsx
@@ -0,0 +1,163 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+
+import { Button, InputSelect, InputText, TextArea } from '@edx/paragon';
+import { formTypes } from '../../data/constants/formTypes';
+
+class EntitlementForm extends React.Component {
+ constructor(props) {
+ super(props);
+
+ if (props.formType === formTypes.REISSUE) {
+ const { courseUuid, mode, user } = props.entitlement;
+ this.state = {
+ courseUuid,
+ mode,
+ username: user,
+ comments: '',
+ };
+ } else {
+ this.state = {
+ courseUuid: '',
+ mode: '',
+ username: '',
+ comments: '',
+ };
+ }
+
+ this.onClose = this.onClose.bind(this);
+ this.handleCourseUUIDChange = this.handleCourseUUIDChange.bind(this);
+ this.handleUsernameChange = this.handleUsernameChange.bind(this);
+ this.handleModeChange = this.handleModeChange.bind(this);
+ this.handleCommentsChange = this.handleCommentsChange.bind(this);
+ this.submitForm = this.submitForm.bind(this);
+ }
+
+ onClose() {
+ this.props.closeForm();
+ }
+
+ handleCourseUUIDChange(courseUuid) {
+ this.setState({ courseUuid });
+ }
+
+ handleUsernameChange(username) {
+ this.setState({ username });
+ }
+
+ handleModeChange(mode) {
+ this.setState({ mode });
+ }
+
+ handleCommentsChange(comments) {
+ this.setState({ comments });
+ }
+
+ submitForm() {
+ const { courseUuid, username, mode, comments } = this.state;
+ const { formType, entitlement } = this.props;
+ if (formType === formTypes.REISSUE) { // if there is an active entitlement we are updating an entitlement
+ this.props.reissueEntitlement({ entitlement, comments });
+ } else { // if there is no active entitlement we are creating a new entitlement
+ this.props.createEntitlement({ courseUuid, username, mode, comments });
+ }
+ }
+
+ render() {
+ const { courseUuid, username, mode, comments } = this.state;
+ const isReissue = this.props.formType === formTypes.REISSUE;
+ const title = isReissue ? 'Re-issue Entitlement' : 'Create Entitlement';
+
+ const body = (
+
+
{title}
+
+
+
+
+
+
+
+
+
+ );
+
+ return this.props.isOpen && body;
+ }
+}
+
+EntitlementForm.propTypes = {
+ formType: PropTypes.string.isRequired,
+ isOpen: PropTypes.bool.isRequired,
+ entitlement: PropTypes.shape({
+ uuid: PropTypes.string.isRequired,
+ courseUuid: PropTypes.string.isRequired,
+ created: PropTypes.string.isRequired,
+ modified: PropTypes.string.isRequired,
+ expiredAt: PropTypes.string,
+ mode: PropTypes.string.isRequired,
+ orderNumber: PropTypes.string,
+ supportDetails: PropTypes.arrayOf(PropTypes.shape({
+ supportUser: PropTypes.string,
+ action: PropTypes.string,
+ comments: PropTypes.string,
+ unenrolledRun: PropTypes.string,
+ })),
+ user: PropTypes.string.isRequired,
+ }),
+ createEntitlement: PropTypes.func.isRequired,
+ reissueEntitlement: PropTypes.func.isRequired,
+ closeForm: PropTypes.func.isRequired,
+};
+
+EntitlementForm.defaultProps = {
+ entitlement: {
+ uuid:'',
+ courseUuid: '',
+ created: '',
+ modified: '',
+ expiredAt: '',
+ mode: 'verified',
+ orderNumber: '',
+ supportDetails: [],
+ user: '',
+ }
+};
+
+export default EntitlementForm;
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
index 214870151f..7a30cbd6f0 100644
--- a/lms/djangoapps/support/static/support/jsx/entitlements/components/Main/Main.jsx
+++ b/lms/djangoapps/support/static/support/jsx/entitlements/components/Main/Main.jsx
@@ -1,9 +1,10 @@
import React from 'react';
import PropTypes from 'prop-types';
-import { StatusAlert } from '@edx/paragon';
+import { Button, StatusAlert } from '@edx/paragon';
import SearchContainer from '../Search/SearchContainer.jsx';
import EntitlementSupportTableContainer from '../Table/EntitlementSupportTableContainer.jsx';
+import EntitlementFormContainer from '../EntitlementForm/container.jsx';
const Main = props => (
@@ -14,17 +15,45 @@ const Main = props => (
open={!!props.errorMessage}
/>
- Entitlement Support Page
+ Student Support: Entitlement
-
-
+
);
+const MainContent = (props) => {
+ if (props.isFormOpen) {
+ return ;
+ }
+ return (
+
+
+
+
+
+ );
+};
+
Main.propTypes = {
errorMessage: PropTypes.string.isRequired,
dismissErrorMessage: PropTypes.func.isRequired,
+ openCreationForm: PropTypes.func.isRequired,
ecommerceUrl: PropTypes.string.isRequired,
+ isFormOpen: PropTypes.bool.isRequired,
+};
+
+MainContent.propTypes = {
+ openCreationForm: PropTypes.func.isRequired,
+ ecommerceUrl: PropTypes.string.isRequired,
+ isFormOpen: PropTypes.bool.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
index 39c342b0a1..25c0644869 100644
--- a/lms/djangoapps/support/static/support/jsx/entitlements/components/Main/MainContainer.jsx
+++ b/lms/djangoapps/support/static/support/jsx/entitlements/components/Main/MainContainer.jsx
@@ -1,15 +1,19 @@
import { connect } from 'react-redux';
import { dismissError } from '../../data/actions/error';
+import { openCreationForm } from '../../data/actions/form';
+
import Main from './Main.jsx';
const mapStateToProps = state => ({
errorMessage: state.error,
+ isFormOpen: state.form.isOpen,
});
const mapDispatchToProps = dispatch => ({
dismissErrorMessage: () => dispatch(dismissError()),
+ openCreationForm: () => dispatch(openCreationForm()),
});
const MainContainer = connect(
diff --git a/lms/djangoapps/support/static/support/jsx/entitlements/components/Table/EntitlementSupportTable.jsx b/lms/djangoapps/support/static/support/jsx/entitlements/components/Table/EntitlementSupportTable.jsx
index ff9023fec4..076ab6898f 100644
--- a/lms/djangoapps/support/static/support/jsx/entitlements/components/Table/EntitlementSupportTable.jsx
+++ b/lms/djangoapps/support/static/support/jsx/entitlements/components/Table/EntitlementSupportTable.jsx
@@ -2,7 +2,7 @@ import React from 'react';
import moment from 'moment';
import PropTypes from 'prop-types';
-import { Hyperlink, Table } from '@edx/paragon';
+import { Button, Hyperlink, Table } from '@edx/paragon';
const entitlementColumns = [
{
@@ -13,14 +13,14 @@ const entitlementColumns = [
label: 'Course UUID',
key: 'courseUuid',
},
- {
- label: 'Enrollment',
- key: 'enrollmentCourseRun',
- },
{
label: 'Mode',
key: 'mode',
},
+ {
+ label: 'Enrollment',
+ key: 'enrollmentCourseRun',
+ },
{
label: 'Expired At',
key: 'expiredAt',
@@ -45,9 +45,9 @@ const entitlementColumns = [
},
];
-const parseEntitlementData = (entitlements, ecommerceUrl) =>
+const parseEntitlementData = (entitlements, ecommerceUrl, openReissueForm) =>
entitlements.map((entitlement) => {
- const { expiredAt, created, modified, orderNumber } = entitlement;
+ const { expiredAt, created, modified, orderNumber, enrollmentCourseRun } = entitlement;
return Object.assign({}, entitlement, {
expiredAt: expiredAt ? moment(expiredAt).format('lll') : '',
createdAt: moment(created).format('lll'),
@@ -56,13 +56,18 @@ const parseEntitlementData = (entitlements, ecommerceUrl) =>
destination={`${ecommerceUrl}${orderNumber}/`}
content={orderNumber || ''}
/>,
- button: No Actions Currently Available
,
+ button: