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

feat: assign by course run implementation #1292

Merged
merged 23 commits into from
Sep 17, 2024
Merged

feat: assign by course run implementation #1292

merged 23 commits into from
Sep 17, 2024

Conversation

brobro10000
Copy link
Contributor

@brobro10000 brobro10000 commented Sep 3, 2024

Ability to assign learner credit assignments by individual course runs. This is a hard cutover from assigning from the top level course key to the individual course run.
Displays an enroll-by date for each applicable course run that currently verifies that the enroll-by date of the course run is before the subsidyExpirationDate- MAX_ALLOWABLE_REFUND_THRESHOLD_DAYS to ensure course runs that are far in the future beyond the policies term are not displayed but respect the ability to provide refunds within the subsidy expiration date.

This PR also includes:

  • Updates display of prices to include a range if multiple unique prices are available for runs based on content_price
  • Updates course page url on the allocation table to the correct URL (courseRun key --> top level key)
  • Update heuristic that determines displaying start date for self paced courses based whether the user has time to complete the course or within 14 days of today. If not, default the start_date to today
  • Supports the late enrollment flow for displaying course runs by determining if the policy allows the user to display late enrollment runs.
  • Updates tests and sample algolia return to include course_runs to accurately test the changes.

Catalog search results card.
Screenshot 2024-09-05 at 12 40 50 PM

Allocation screen:
Screenshot 2024-09-05 at 12 41 09 PM

Zero state was also added for edge cases that the enroll-by date for all course runs is beyond the subsidyExpirationDate+STALE_ENROLLMENT_DROPOFF_DAYS threshold
Catalog search zero state:
Screenshot 2024-09-05 at 12 49 20 PM

For all changes

  • Ensure adequate tests are in place (or reviewed existing tests cover changes)

Only if submitting a visual change

  • Ensure to attach screenshots
  • Ensure to have UX team confirm screenshots

@brobro10000 brobro10000 force-pushed the hu/ent-8878 branch 4 times, most recently from 5473422 to 6411917 Compare September 5, 2024 16:35
Copy link

codecov bot commented Sep 5, 2024

Codecov Report

Attention: Patch coverage is 91.01796% with 15 lines in your changes missing coverage. Please review.

Project coverage is 85.64%. Comparing base (d1a270f) to head (b5f6cd3).
Report is 1 commits behind head on master.

Files with missing lines Patch % Lines
...components/learner-credit-management/data/utils.js 78.00% 9 Missing and 2 partials ⚠️
...ent-modal/AssignmentAllocationHelpCollapsibles.jsx 91.66% 1 Missing ⚠️
.../assignment-modal/AssignmentModalmportantDates.jsx 94.73% 1 Missing ⚠️
...ment/assignment-modal/NewAssignmentModalButton.jsx 85.71% 1 Missing ⚠️
...it-management/cards/data/useCourseCardMetadata.jsx 96.87% 1 Missing ⚠️
Additional details and impacted files
@@            Coverage Diff             @@
##           master    #1292      +/-   ##
==========================================
+ Coverage   85.60%   85.64%   +0.04%     
==========================================
  Files         566      567       +1     
  Lines       12467    12590     +123     
  Branches     2602     2634      +32     
==========================================
+ Hits        10672    10783     +111     
- Misses       1737     1748      +11     
- Partials       58       59       +1     

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

@brobro10000 brobro10000 marked this pull request as ready for review September 5, 2024 16:51
@brobro10000 brobro10000 force-pushed the hu/ent-8878 branch 4 times, most recently from 25667e8 to e1e7ec9 Compare September 6, 2024 15:06
src/components/AdvanceAnalyticsV2/charts/ChartWrapper.jsx Outdated Show resolved Hide resolved
const [emptyState] = useState(courseRuns.length === 0);
return (
<Dropdown id={courseKey}>
<Dropdown.Toggle variant="primary" id="assign-by-course-runs-dropdown">
Copy link
Member

Choose a reason for hiding this comment

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

Given there are multiple "Assign" CTAs rendered in the search results, I believe this id should be unique per search result?

Copy link
Contributor Author

@brobro10000 brobro10000 Sep 11, 2024

Choose a reason for hiding this comment

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

The NewAssisgnmentModalButton component passes a top level course courseKey value to each dropdown component (each card result). Logging the output of each id on the top level <Dropdown /> (iamge 1) and <Dropdown.Item /> (image 2) component show that they are unique 👍🏽
Screenshot 2024-09-11 at 3 13 56 PM
Screenshot 2024-09-11 at 3 14 38 PM

Copy link
Member

Choose a reason for hiding this comment

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

What about id="assign-by-course-runs-dropdown", though? Is the id on the top-level Dropdown necessary? On the Paragon docs site, it looks like it's only passed on the Dropdown.Toggle. Should the courseKey be included as part of this id to make it unique?

return (
<section className="assignments-important-dates small">
{enrollByDate && (
<AssignmentModalImportantDate label={intl.formatMessage(messages.enrollByDate)}>
Copy link
Member

Choose a reason for hiding this comment

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

Nice abstraction of AssignmentModalImportantDate :)

@brobro10000 brobro10000 force-pushed the hu/ent-8878 branch 6 times, most recently from 201ce8b to 7a8f7ca Compare September 12, 2024 18:55
Comment on lines +79 to +87
const footerText = intl.formatMessage(messages.courseFooterMessage, {
courseRuns: assignableCourseRuns.length,
pluralText: pluralText('date', assignableCourseRuns.length),
});
Copy link
Member

Choose a reason for hiding this comment

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

nice construction of the i18n message here!

@@ -22,6 +22,12 @@ export const API_FIELDS_BY_TABLE_COLUMN_ACCESSOR = {
courseListPrice: 'course_list_price',
};

// Course pace text
Copy link
Member

Choose a reason for hiding this comment

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

Thank you for making sure we stick to a single constants file within this module 🙌

return weeksToComplete <= differenceInWeeks;
};

const isWithinMinimumStartDateThreshold = ({ start }) => dayjs(start).isBefore(dayjs().subtract(START_DATE_DEFAULT_TO_TODAY_THRESHOLD_DAYS, 'days'));
Copy link
Member

Choose a reason for hiding this comment

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

👨‍🍳 💋

src/index.scss Outdated Show resolved Hide resolved
* @param punctuation
* @returns {string}
*/
const pluralText = (
Copy link
Member

Choose a reason for hiding this comment

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

[inform] I think what you have here is fine, but just as a heads up, it looks like there is some support for defining plural messages within the message format (ICU syntax, see https://formatjs.io/docs/core-concepts/icu-syntax/#plural-format) or perhaps FormattedPlural (docs).

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Leaving comment open as reference 👍🏽

@brobro10000 brobro10000 force-pushed the hu/ent-8878 branch 4 times, most recently from ec4be07 to f75e9d1 Compare September 16, 2024 18:23
// Maximum days allowed from enrollment for a refund on assignments related to policies
export const MAX_ALLOWABLE_REFUND_THRESHOLD_DAYS = 14;

// Start date threshold to default to today days, sets start date to today if course start date is beyond this value
Copy link
Contributor

Choose a reason for hiding this comment

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

Nit:

Suggested change
// Start date threshold to default to today days, sets start date to today if course start date is beyond this value
// When the start date is before this number of days before today, display the alternate start date (fixed to today).

@brobro10000 brobro10000 force-pushed the hu/ent-8878 branch 2 times, most recently from a3687dd to d1b71e3 Compare September 17, 2024 14:21
Comment on lines 31 to 33
start: mockCurrentStartDate,
end: dayjs(mockCurrentStartDate).add(1, 'year').toISOString(),
enroll_by: dayjs(mockCurrentStartDate).unix(),
Copy link
Member

Choose a reason for hiding this comment

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

nit: curious whether we can either rename this mock date to be more generic or have separate variables to use for each related field.

As is, the mockCurrentStartDate is being used for end/enroll_by dates, too which could be a bit misleading/confusing.

@@ -111,6 +111,9 @@ export const START_DATE_DEFAULT_TO_TODAY_THRESHOLD_DAYS = 14;
// Default empty content_price value
export const EMPTY_CONTENT_PRICE_VALUE = 0;

//
Copy link
Member

Choose a reason for hiding this comment

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

nit: empty comment

),
);
}
if (hasCourseStarted(enrollBy) && isLateRedemptionAllowed) {
Copy link
Member

@adamstankiewicz adamstankiewicz Sep 17, 2024

Choose a reason for hiding this comment

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

nit: Should we be using a function hasCourseStarted with an enrollBy date (seems somewhat misleading/confusing)? Perhaps this util function should be renamed to be more generic, so it's not tied explicitly to "start" dates based on its name.

Comment on lines 596 to 601
isEligibleForEnrollment = dayjs(enrollBy).isBefore(
Math.min(
dayjs(subsidyExpirationDatetime).subtract(MAX_ALLOWABLE_REFUND_THRESHOLD_DAYS, 'days').toDate(),
dayjs().add(DAYS_UNTIL_ASSIGNMENT_ALLOCATION_EXPIRATION, 'days').toDate(),
),
);
Copy link
Contributor

@pwnage101 pwnage101 Sep 17, 2024

Choose a reason for hiding this comment

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

You sure just changing this to min is sufficient? The docstring was updated to match this logic, but still the desired outcome is not explicitly stated. If the goal is as I described it previously, then I think this is still incorrect because it guarantees that learners ALWAYS have less than 90 days to accept an assignment.

* - If hasEnrollBy, we return assignments with enroll before the soonest of the two date: The subsidy expiration
* date - refund threshold OR today offset by the 90-day allocation threshold for an assignment denoted as
* isEligibleForEnrollment
* - If hasEnrollBy, we return assignments with enroll before the soonest date: The subsidy expiration
Copy link
Member

Choose a reason for hiding this comment

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

nit: enroll -> enrollBy (deferred)

src/components/learner-credit-management/data/utils.js Outdated Show resolved Hide resolved
@brobro10000 brobro10000 merged commit 5619bad into master Sep 17, 2024
6 checks passed
@brobro10000 brobro10000 deleted the hu/ent-8878 branch September 17, 2024 19:47
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.

3 participants