From 96b3e150e58af4298879b25b17ed83ef3bc9f5a3 Mon Sep 17 00:00:00 2001 From: Ali-D-Akbar Date: Thu, 21 Jan 2021 18:57:52 +0500 Subject: [PATCH] add ability to expire entitlements --- src/users/UserPage.jsx | 2 +- src/users/data/api.js | 37 +---- .../CreateEntitlementForm.jsx} | 98 ++++--------- src/users/entitlements/EntitlementActions.jsx | 3 + src/users/{ => entitlements}/Entitlements.jsx | 129 ++++++++++-------- .../entitlements/ExpireEntitlementForm.jsx | 118 ++++++++++++++++ src/users/entitlements/PropTypes.jsx | 31 +++++ .../entitlements/ReissueEntitlementForm.jsx | 116 ++++++++++++++++ src/users/entitlements/RenderForm.jsx | 65 +++++++++ 9 files changed, 437 insertions(+), 162 deletions(-) rename src/users/{EntitlementForm.jsx => entitlements/CreateEntitlementForm.jsx} (56%) create mode 100644 src/users/entitlements/EntitlementActions.jsx rename src/users/{ => entitlements}/Entitlements.jsx (69%) create mode 100644 src/users/entitlements/ExpireEntitlementForm.jsx create mode 100644 src/users/entitlements/PropTypes.jsx create mode 100644 src/users/entitlements/ReissueEntitlementForm.jsx create mode 100644 src/users/entitlements/RenderForm.jsx diff --git a/src/users/UserPage.jsx b/src/users/UserPage.jsx index 82e71cf60..13f3beca9 100644 --- a/src/users/UserPage.jsx +++ b/src/users/UserPage.jsx @@ -11,7 +11,7 @@ import UserMessagesContext from '../user-messages/UserMessagesContext'; import { isEmail, isValidUsername } from '../utils/index'; import { getAllUserData } from './data/api'; import Enrollments from './Enrollments'; -import Entitlements from './Entitlements'; +import Entitlements from './entitlements/Entitlements'; import UserSearch from './UserSearch'; import UserSummary from './UserSummary'; diff --git a/src/users/data/api.js b/src/users/data/api.js index 436915fc2..dfb7ac7a2 100644 --- a/src/users/data/api.js +++ b/src/users/data/api.js @@ -221,24 +221,11 @@ export async function getCourseData(courseUUID) { } export async function patchEntitlement({ - uuid, - action, - unenrolledRun = null, - comments = null, + uuid, requestData, }) { try { const { data } = await getAuthenticatedHttpClient().patch( - `${getConfig().LMS_BASE_URL}/api/entitlements/v1/entitlements/${uuid}/`, - { - expired_at: null, - support_details: [ - { - unenrolled_run: unenrolledRun, - action, - comments, - }, - ], - }, + `${getConfig().LMS_BASE_URL}/api/entitlements/v1/entitlements/${uuid}/`, requestData, ); return data; } catch (error) { @@ -265,27 +252,11 @@ export async function patchEntitlement({ } export async function postEntitlement({ - user, - courseUuid, - mode, - action, - comments = null, + requestData, }) { try { const { data } = await getAuthenticatedHttpClient().post( - `${getConfig().LMS_BASE_URL}/api/entitlements/v1/entitlements/`, - { - course_uuid: courseUuid, - user, - mode, - refund_locked: true, - support_details: [ - { - action, - comments, - }, - ], - }, + `${getConfig().LMS_BASE_URL}/api/entitlements/v1/entitlements/`, requestData, ); return data; } catch (error) { diff --git a/src/users/EntitlementForm.jsx b/src/users/entitlements/CreateEntitlementForm.jsx similarity index 56% rename from src/users/EntitlementForm.jsx rename to src/users/entitlements/CreateEntitlementForm.jsx index 934489ab3..5ff351a8c 100644 --- a/src/users/EntitlementForm.jsx +++ b/src/users/entitlements/CreateEntitlementForm.jsx @@ -5,15 +5,13 @@ import { } from '@edx/paragon'; import classNames from 'classnames'; -import UserMessagesContext from '../user-messages/UserMessagesContext'; -import AlertList from '../user-messages/AlertList'; -import { postEntitlement, patchEntitlement } from './data/api'; +import UserMessagesContext from '../../user-messages/UserMessagesContext'; +import AlertList from '../../user-messages/AlertList'; +import { postEntitlement } from '../data/api'; +import { CREATE } from './EntitlementActions'; +import { EntitlementPropTypes, EntitlementDefaultProps } from './PropTypes'; -export const REISSUE = 'reissue'; -export const CREATE = 'create'; - -export default function EntitlementForm({ - formType, +export default function CreateEntitlementForm({ entitlement, changeHandler, closeHandler, @@ -27,50 +25,36 @@ export default function EntitlementForm({ const submit = useCallback(() => { clear('entitlements'); - if (formType === CREATE) { - postEntitlement({ + postEntitlement({ + requestData: { + course_uuid: courseUuid, user, - courseUuid, mode, - action: CREATE, - comments, - }).then((result) => { - if (result.errors !== undefined) { - result.errors.forEach(error => add(error)); - } else { - changeHandler(); - } - }); - } else if (formType === REISSUE) { - patchEntitlement({ - uuid: entitlement.uuid, - action: REISSUE, - unenrolledRun: entitlement.enrollmentCourseRun, - comments, - }).then((result) => { - if (result.errors !== undefined) { - result.errors.forEach(error => add(error)); - } else { - changeHandler(); - } - }); - } + refund_locked: true, + support_details: [{ + action: CREATE, + comments, + }], + }, + }).then((result) => { + if (result.errors !== undefined) { + result.errors.forEach(error => add(error)); + } else { + changeHandler(); + } + }); }); - const isReissue = formType === REISSUE; - const title = isReissue ? 'Re-issue Entitlement' : 'Create Entitlement'; - return (
-

{title}

+

Create Entitlement

All fields are required
Mode ({ + return data.results.map(entitlement => ({ courseUuid: { displayValue: ( ), - value: result.courseUuid, + value: entitlement.courseUuid, }, mode: { - value: result.mode, + value: entitlement.mode, }, enrollment: { - displayValue: (result.enrollmentCourseRun ? ( + displayValue: (entitlement.enrollmentCourseRun ? ( - {result.enrollmentCourseRun} + {entitlement.enrollmentCourseRun} ) : 'Course Run Not Selected'), - value: result.enrollmentCourseRun, + value: entitlement.enrollmentCourseRun, }, expiredAt: { - displayValue: formatDate(result.expiredAt), - value: result.expiredAt, + displayValue: formatDate(entitlement.expiredAt), + value: entitlement.expiredAt, }, created: { - displayValue: formatDate(result.created), - value: result.created, + displayValue: formatDate(entitlement.created), + value: entitlement.created, }, modified: { - displayValue: formatDate(result.modified), - value: result.modified, + displayValue: formatDate(entitlement.modified), + value: entitlement.modified, }, orderNumber: { displayValue: ( - {result.orderNumber} + {entitlement.orderNumber} ), - value: result.orderNumber, + value: entitlement.orderNumber, }, actions: { displayValue: ( - +
+ + +
), value: 'Resissue', }, @@ -173,7 +188,7 @@ export default function Entitlements({ label: 'Order', key: 'orderNumber', columnSortable: true, onSort: () => setSort('orderNumber'), width: 'col-3', }, { - label: 'Actions', key: 'actions', columnSortable: true, onSort: () => {}, width: 'col-3', + label: 'Actions', key: 'actions', columnSortable: true, onSort: () => { }, width: 'col-3', }, ]; @@ -183,32 +198,32 @@ export default function Entitlements({
{!formType && ( - + )}
{formType !== null ? ( - {}} + submitHandler={() => { }} closeHandler={() => setFormType(null)} forwardedRef={formRef} /> - ) : () } + ) : ()} {courseSummaryUUID !== null ? ( @@ -222,7 +237,7 @@ export default function Entitlements({ errors={courseSummaryErrors} forwardedRef={summaryRef} /> - ) : () } + ) : ()} { + const now = new Date().toISOString(); + clear('entitlements'); + patchEntitlement({ + uuid: entitlement.uuid, + requestData: { + expired_at: now, + support_details: [{ + unenrolled_run: entitlement.enrollmentCourseRun, + action: EXPIRE, + comments, + }], + }, + }).then((result) => { + if (result.errors !== undefined) { + result.errors.forEach(error => add(error)); + } else { + changeHandler(); + } + }); + }); + + return ( +
+ + +

Expire Entitlement

+
All fields are required
+
+ + setCourseUuid(event.target.value)} + disabled + /> +
+
+ + setMode(event.target.value)} + disabled + /> +
+
+ + setComments(event.target.value)} + ref={forwardedRef} + /> +
+
+ + +
+ +
+ ); +} + +ExpireEntitlementForm.propTypes = { + entitlement: EntitlementPropTypes, + changeHandler: PropTypes.func.isRequired, + closeHandler: PropTypes.func.isRequired, + forwardedRef: PropTypes.shape({ current: PropTypes.instanceOf(Element) }), +}; + +ExpireEntitlementForm.defaultProps = { + entitlement: EntitlementDefaultProps, + forwardedRef: null, +}; diff --git a/src/users/entitlements/PropTypes.jsx b/src/users/entitlements/PropTypes.jsx new file mode 100644 index 000000000..bcc1d10a4 --- /dev/null +++ b/src/users/entitlements/PropTypes.jsx @@ -0,0 +1,31 @@ +import PropTypes from 'prop-types'; + +export const EntitlementPropTypes = PropTypes.shape({ + uuid: PropTypes.string.isRequired, + courseUuid: PropTypes.string.isRequired, + enrollmentCourseRun: PropTypes.string, + 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, +}); + +export const EntitlementDefaultProps = { + uuid: '', + courseUuid: '', + created: '', + modified: '', + expiredAt: '', + mode: 'verified', + orderNumber: '', + supportDetails: [], + user: '', +}; diff --git a/src/users/entitlements/ReissueEntitlementForm.jsx b/src/users/entitlements/ReissueEntitlementForm.jsx new file mode 100644 index 000000000..ad25675e4 --- /dev/null +++ b/src/users/entitlements/ReissueEntitlementForm.jsx @@ -0,0 +1,116 @@ +import React, { useCallback, useState, useContext } from 'react'; +import PropTypes from 'prop-types'; +import { + Button, Input, +} from '@edx/paragon'; +import classNames from 'classnames'; + +import UserMessagesContext from '../../user-messages/UserMessagesContext'; +import AlertList from '../../user-messages/AlertList'; +import { patchEntitlement } from '../data/api'; +import { REISSUE } from './EntitlementActions'; +import { EntitlementPropTypes, EntitlementDefaultProps } from './PropTypes'; + +export default function ReissueEntitlementForm({ + entitlement, + changeHandler, + closeHandler, + forwardedRef, +}) { + const [courseUuid, setCourseUuid] = useState(entitlement.courseUuid); + const [mode, setMode] = useState(entitlement.mode); + const [comments, setComments] = useState(''); + const { add, clear } = useContext(UserMessagesContext); + + const submit = useCallback(() => { + clear('entitlements'); + patchEntitlement({ + uuid: entitlement.uuid, + requestData: { + support_details: [{ + unenrolled_run: entitlement.enrollmentCourseRun, + action: REISSUE, + comments, + }], + }, + }).then((result) => { + if (result.errors !== undefined) { + result.errors.forEach((error) => add(error)); + } else { + changeHandler(); + } + }); + }); + + return ( +
+
+ +

Reissue Entitlement

+
All fields are required
+
+ + setCourseUuid(event.target.value)} + disabled + /> +
+
+ + setMode(event.target.value)} + disabled + /> +
+
+ + setComments(event.target.value)} + ref={forwardedRef} + /> +
+
+ + +
+ +
+ ); +} + +ReissueEntitlementForm.propTypes = { + entitlement: EntitlementPropTypes, + changeHandler: PropTypes.func.isRequired, + closeHandler: PropTypes.func.isRequired, + forwardedRef: PropTypes.shape({ current: PropTypes.instanceOf(Element) }), +}; + +ReissueEntitlementForm.defaultProps = { + entitlement: EntitlementDefaultProps, + forwardedRef: null, +}; diff --git a/src/users/entitlements/RenderForm.jsx b/src/users/entitlements/RenderForm.jsx new file mode 100644 index 000000000..29dc10eac --- /dev/null +++ b/src/users/entitlements/RenderForm.jsx @@ -0,0 +1,65 @@ +import React from 'react'; +import PropTypes from 'prop-types'; +import { CREATE, REISSUE, EXPIRE } from './EntitlementActions'; +import CreateEntitlementForm from './CreateEntitlementForm'; +import ReissueEntitlementForm from './ReissueEntitlementForm'; +import ExpireEntitlementForm from './ExpireEntitlementForm'; +import { EntitlementPropTypes, EntitlementDefaultProps } from './PropTypes'; + +export default function RenderForm({ + formType, + entitlement, + changeHandler, + closeHandler, + user, + forwardedRef, +}) { + if (formType === CREATE) { + return ( + + ); + } if (formType === EXPIRE) { + return ( + + ); + } if (formType === REISSUE) { + return ( + + ); + } +} + +RenderForm.propTypes = { + formType: PropTypes.string.isRequired, + entitlement: EntitlementPropTypes, + user: PropTypes.string.isRequired, + changeHandler: PropTypes.func.isRequired, + closeHandler: PropTypes.func.isRequired, + forwardedRef: PropTypes.shape({ current: PropTypes.instanceOf(Element) }), +}; + +RenderForm.defaultProps = { + entitlement: EntitlementDefaultProps, + forwardedRef: null, +};