Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add ability to expire Entitlements #83

Merged
merged 1 commit into from
Feb 1, 2021
Merged

Conversation

Ali-D-Akbar
Copy link
Contributor

@Ali-D-Akbar Ali-D-Akbar commented Jan 21, 2021

Add ability to expire entitlements in support tool

PROD-2132

An Expire button is added in the action column of Entitlements as shown in the image:

Screenshot 2021-01-21 at 6 49 58 PM

A form will be shown upon clicking the Expire button. The user can add a comment about the reason to expire the entitlement.
Screenshot 2021-01-21 at 6 51 00 PM

Submitting this will send a patch request to api to set expiredAt field. Note that the button will be disabled once the entitlement is expired.
Screenshot 2021-01-21 at 6 52 52 PM

@codecov
Copy link

codecov bot commented Jan 21, 2021

Codecov Report

Merging #83 (bad2e8e) into master (f40697d) will decrease coverage by 0.02%.
The diff coverage is 18.57%.

Impacted file tree graph

@@            Coverage Diff             @@
##           master      #83      +/-   ##
==========================================
- Coverage   21.86%   21.83%   -0.03%     
==========================================
  Files          28       34       +6     
  Lines         709      751      +42     
  Branches      152      155       +3     
==========================================
+ Hits          155      164       +9     
- Misses        539      572      +33     
  Partials       15       15              
Impacted Files Coverage Δ
src/users/UserPage.jsx 62.16% <ø> (ø)
src/users/data/api.js 26.80% <ø> (ø)
src/users/entitlements/Entitlements.jsx 2.81% <0.00%> (ø)
src/users/entitlements/utils.js 0.00% <0.00%> (ø)
src/users/entitlements/ExpireEntitlementForm.jsx 11.11% <11.11%> (ø)
src/users/entitlements/ReissueEntitlementForm.jsx 11.76% <11.76%> (ø)
src/users/entitlements/EntitlementForm.jsx 25.00% <25.00%> (ø)
src/users/entitlements/CreateEntitlementForm.jsx 11.76% <33.33%> (ø)
src/users/entitlements/EntitlementActions.jsx 100.00% <100.00%> (ø)
src/users/entitlements/PropTypes.jsx 100.00% <100.00%> (ø)
... and 6 more

Continue to review full report at Codecov.

Legend - Click here to learn more
Δ = absolute <relative> (impact), ø = not affected, ? = missing data
Powered by Codecov. Last update f40697d...2fe77b5. Read the comment docs.

@Ali-D-Akbar Ali-D-Akbar changed the title add ability to expire entitlements Add ability to expire Entitlements Jan 21, 2021
Copy link

@saadyousafarbi saadyousafarbi left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Before review had some questions regarding the AC of the ticket being shared:

  • Record the name of the support person expiring the entitlement, the time of expiration, and the reason for expiration.
    Is this being captured anywhere on this new flow?

  • If there are two entitlements appearing in a course for a user, expiring one shouldn’t impact the other in any way.
    Have you tested this scenario, with learners having two entitlements for the same course? Looks like it shouldnt be a problem... But just to make sure!

@Ali-D-Akbar
Copy link
Contributor Author

Ali-D-Akbar commented Jan 22, 2021

  • Record the name of the support person expiring the entitlement, the time of expiration, and the reason for expiration.
    Is this being captured anywhere on this new flow?

The API handles this very purpose as you can see below.
Screenshot 2021-01-22 at 3 20 01 PM

  • If there are two entitlements appearing in a course for a user, expiring one shouldn’t impact the other in any way.
    Have you tested this scenario, with learners having two entitlements for the same course? Looks like it shouldnt be a problem... But just to make sure!

We're making a patch request to the API with the uuid of the entitlement instead of course_uuid. This will only expire the specific entitlement.

Copy link
Contributor

@awaisdar001 awaisdar001 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

need some improvements here.

comments,
},
],
expired_at: ((action === EXPIRE) ? now : null),
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This API layer shouldn't construct data -- and it should use the data. so, please if you are passing this request data it's better (for clarity) to pass from the calling function.

In the future if we want to reuse patchEntitlement method we would not need to come back here and add another if condition.

@@ -0,0 +1,3 @@
export const REISSUE = 'reissue';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍


export default function EntitlementForm({
formType,
export default function EntitlementCreateForm({
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Better => CreateEntitlementForm

});

const isReissue = formType === REISSUE;
const title = isReissue ? 'Re-issue Entitlement' : 'Create Entitlement';
let title = 'Create Entitlement';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

why let than const here?

clear('entitlements');
patchEntitlement({
uuid: entitlement.uuid,
action: EXPIRE,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here you should pass the data you want to patch, don't expose app logic to the API layer.

}) {
const [courseUuid, setCourseUuid] = useState(entitlement.courseUuid);
const [mode, setMode] = useState(entitlement.mode);
const [comments, setComments] = useState('');
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

comments => comment

forwardedRef={forwardedRef}
/>
);
default:
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Let's use if/else here. switch/case is preferred if the number of cases are more than 5 AFAIK.

src/users/entitlements/EntitlementForm.jsx Show resolved Hide resolved
};

EntitlementForm.defaultProps = {
entitlement: {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same goes here.

clear('entitlements');
patchEntitlement({
uuid: entitlement.uuid,
action: REISSUE,
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same comments here.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What must be updated here? I've updated everything else except this.

@@ -25,8 +26,7 @@ export default function EntitlementForm({
forwardedRef={forwardedRef}
/>
);
}
else if (formType === EXPIRE) {
} if (formType === EXPIRE) {
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Only one form is rendering at one time so what do you think about using if/else?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Had to change it because of eslint error no-else-return
(It's weird how eslint reacts to 3 cases of if/else.)

@@ -225,19 +225,18 @@ export async function patchEntitlement({
action,
unenrolledRun = null,
comments = null,
expiredAt = null,
}) {
try {
const { data } = await getAuthenticatedHttpClient().patch(
`${getConfig().LMS_BASE_URL}/api/entitlements/v1/entitlements/${uuid}/`,
{
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My understanding was when I commented previously, is to struct the following data from the calling function so API layer.

  {
        expired_at: expiredAt,
        support_details: [{
          unenrolled_run: unenrolledRun,
          action,
          comments,
        }],
      },


const isReissue = formType === REISSUE;
const title = isReissue ? 'Re-issue Entitlement' : 'Create Entitlement';
const title = 'Create Entitlement';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Any reason for having this variable in place? is being reused anywhere? If it's only used in one place then this variable is not useful.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

You're right. I'm removing the variable and use the text directly.

@@ -0,0 +1,66 @@
import React from 'react';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the name of this file can be improved to RenderForm.jsx

@@ -0,0 +1,31 @@
import PropTypes from 'prop-types';
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

src/users/entitlements/PropTypes.jsx

disabled={!result.enrollmentCourseRun}
onClick={() => {
clearCourseSummary();
setUserEntitlement(result);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

result => entitlement

@Ali-D-Akbar Ali-D-Akbar force-pushed the aakbar/PROD-2132 branch 2 times, most recently from a41d3cd to 397cb5b Compare January 27, 2021 07:18
@@ -221,24 +221,11 @@ export async function getCourseData(courseUUID) {
}

export async function patchEntitlement({
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this API call is alot cleaner now. 👍
have you updated all patchEntitlement calls in the code?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, I've changed the calls accordingly and tested it on the local.

@@ -65,76 +66,90 @@ export default function Entitlements({
if (data === null) {
return [];
}
return data.results.map(result => ({
return data.results.map(entitlement => ({
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

more readable with this change 👍

Copy link
Contributor

@awaisdar001 awaisdar001 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the changes look good to me 👍

@Ali-D-Akbar Ali-D-Akbar force-pushed the aakbar/PROD-2132 branch 2 times, most recently from a48330a to 96b3e15 Compare January 29, 2021 12:29
Copy link
Contributor

@DawoudSheraz DawoudSheraz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added a few comments.

import ExpireEntitlementForm from './ExpireEntitlementForm';
import { EntitlementPropTypes, EntitlementDefaultProps } from './PropTypes';

export default function RenderForm({
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the appropriate name would be EntitlementForm. RenderForm doesn't signify what is being rendered.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I originally had it named as EntitlementForm but was asked to change it by @awaisdar001

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, I still think EntitlementForm is a better name. It signifies the form is for entitlement. RenderForm is a generic term because it could be to render anything.

Comment on lines 27 to 35
patchEntitlement({
uuid: entitlement.uuid,
requestData: {
support_details: [{
unenrolled_run: entitlement.enrollmentCourseRun,
action: REISSUE,
comments,
}],
},
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think we can write a utility function that will return the dict representation of the data that API needs. Right now, the representation is being duplicated whenever we need to call API. Although this will not go to the API function itself, having a utility function means that in the future, if the API data signature changes, we will need to update it in fewer places.

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Updated.

<Button
type="button"
variant="outline-danger"
disabled={entitlement.expiredAt}
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Isn't expiredAt a datetime str?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yes, if expiredAtHAS a value other than null then the field will be disabled.

Copy link
Contributor

@DawoudSheraz DawoudSheraz left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

nit comments, otherwise it is good to approve.

Submit
</Button>
<Button
className="btn-outline-secondary"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

use variant here. It might break with paragon 12. Not a blocker but do change it in a followup PR

Submit
</Button>
<Button
className="btn-outline-secondary"
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

same here

@@ -0,0 +1,12 @@
export default function makeRequestData({
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

filename should be utils.js, not makeRequestData

@Ali-D-Akbar Ali-D-Akbar merged commit f77a4fc into master Feb 1, 2021
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

4 participants