-
Notifications
You must be signed in to change notification settings - Fork 19
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
Conversation
Codecov Report
@@ 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
Continue to review full report at Codecov.
|
There was a problem hiding this 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!
There was a problem hiding this 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.
src/users/data/api.js
Outdated
comments, | ||
}, | ||
], | ||
expired_at: ((action === EXPIRE) ? now : null), |
There was a problem hiding this comment.
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'; |
There was a problem hiding this comment.
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({ |
There was a problem hiding this comment.
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'; |
There was a problem hiding this comment.
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, |
There was a problem hiding this comment.
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(''); |
There was a problem hiding this comment.
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: |
There was a problem hiding this comment.
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.
}; | ||
|
||
EntitlementForm.defaultProps = { | ||
entitlement: { |
There was a problem hiding this comment.
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, |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
same comments here.
There was a problem hiding this comment.
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) { |
There was a problem hiding this comment.
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
?
There was a problem hiding this comment.
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.)
src/users/data/api.js
Outdated
@@ -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}/`, | |||
{ |
There was a problem hiding this comment.
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'; |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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'; |
There was a problem hiding this comment.
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'; |
There was a problem hiding this comment.
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); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
result
=> entitlement
4d72748
to
fb67906
Compare
a41d3cd
to
397cb5b
Compare
@@ -221,24 +221,11 @@ export async function getCourseData(courseUUID) { | |||
} | |||
|
|||
export async function patchEntitlement({ |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
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 => ({ |
There was a problem hiding this comment.
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 👍
There was a problem hiding this 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 👍
a48330a
to
96b3e15
Compare
There was a problem hiding this 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({ |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
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
There was a problem hiding this comment.
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.
patchEntitlement({ | ||
uuid: entitlement.uuid, | ||
requestData: { | ||
support_details: [{ | ||
unenrolled_run: entitlement.enrollmentCourseRun, | ||
action: REISSUE, | ||
comments, | ||
}], | ||
}, |
There was a problem hiding this comment.
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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
There was a problem hiding this comment.
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} |
There was a problem hiding this comment.
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?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Yes, if expiredAt
HAS a value other than null
then the field will be disabled.
There was a problem hiding this 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.
e893068
to
1fce864
Compare
Submit | ||
</Button> | ||
<Button | ||
className="btn-outline-secondary" |
There was a problem hiding this comment.
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" |
There was a problem hiding this comment.
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({ |
There was a problem hiding this comment.
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
1fce864
to
2fe77b5
Compare
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:A form will be shown upon clicking the
![Screenshot 2021-01-21 at 6 51 00 PM](https://user-images.githubusercontent.com/52413434/105364634-32259f00-5c1f-11eb-9d32-a4f77778de83.png)
Expire
button. The user can add a comment about the reason to expire the entitlement.Submitting this will send a patch request to api to set
![Screenshot 2021-01-21 at 6 52 52 PM](https://user-images.githubusercontent.com/52413434/105364890-803aa280-5c1f-11eb-9561-c79422869ac3.png)
expiredAt
field. Note that the button will be disabled once the entitlement is expired.