Skip to content

Commit

Permalink
feat: explicitly handle late enrollment case
Browse files Browse the repository at this point in the history
  • Loading branch information
brobro10000 committed Sep 17, 2024
1 parent 765c86d commit 9a899a3
Show file tree
Hide file tree
Showing 5 changed files with 45 additions and 18 deletions.
6 changes: 6 additions & 0 deletions __mocks__/react-instantsearch-dom.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ const fakeHits = [
start: mockCurrentStartDate,
end: dayjs(mockCurrentStartDate).add(1, 'year').toISOString(),
enroll_by: dayjs(mockCurrentStartDate).unix(),
has_enroll_by: true,
is_active: true,
max_effort: 5,
min_effort: 1,
Expand All @@ -47,6 +48,7 @@ const fakeHits = [
start: mockCurrentStartDate,
end: dayjs(mockCurrentStartDate).add(1, 'year').toISOString(),
enroll_by: dayjs(mockCurrentStartDate).unix(),
has_enroll_by: true,
is_active: true,
max_effort: 5,
min_effort: 1,
Expand All @@ -60,6 +62,7 @@ const fakeHits = [
start: '2020-09-09T04:00:00Z',
end: dayjs('2020-09-09T04:00:00Z').add(1, 'year').toISOString(),
enroll_by: dayjs('2020-09-09T04:00:00Z').unix(),
has_enroll_by: true,
is_active: true,
max_effort: 5,
min_effort: 1,
Expand All @@ -82,6 +85,7 @@ const fakeHits = [
start: '2022-10-09T04:00:00Z',
end: dayjs('2022-10-09T04:00:00Z').add(1, 'year').toISOString(),
enroll_by: dayjs('2022-10-09T04:00:00Z').unix(),
has_enroll_by: true,
is_active: true,
max_effort: 5,
min_effort: 1,
Expand All @@ -98,6 +102,7 @@ const fakeHits = [
start: '2022-10-09T04:00:00Z',
end: dayjs('2022-10-09T04:00:00Z').add(1, 'year').toISOString(),
enroll_by: dayjs('2022-10-09T04:00:00Z').unix(),
has_enroll_by: true,
is_active: true,
max_effort: 5,
min_effort: 1,
Expand All @@ -111,6 +116,7 @@ const fakeHits = [
start: '2020-09-09T04:00:00Z',
end: dayjs('2020-09-09T04:00:00Z').add(1, 'year').toISOString(),
enroll_by: dayjs('2020-09-09T04:00:00Z').unix(),
has_enroll_by: true,
is_active: true,
max_effort: 5,
min_effort: 1,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -62,7 +62,6 @@ const useCourseCardMetadata = ({

// Extracts the content price from assignable course runs
const formattedPrice = getContentPriceDisplay({ courseRuns: assignableCourseRuns });

const imageSrc = cardImageUrl || cardFallbackImg;

let logoSrc;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -76,6 +76,7 @@ const originalData = {
upgrade_deadline: 1892678399,
pacing_type: 'self_paced',
enroll_by: enrollByTimestamp,
has_enroll_by: true,
is_active: true,
weeks_to_complete: 60,
end: dayjs().add(1, 'years').toISOString(),
Expand All @@ -88,6 +89,7 @@ const originalData = {
upgrade_deadline: 1892678399,
pacing_type: 'self_paced',
enroll_by: enrollByTimestamp,
has_enroll_by: true,
is_active: true,
weeks_to_complete: 60,
end: dayjs().add(1, 'year').toISOString(),
Expand Down Expand Up @@ -119,7 +121,8 @@ const execEdData = {
start: futureStartDate,
upgrade_deadline: 1892678399,
pacing_type: 'instructor_paced',
enroll_by: 1892678399,
enroll_by: enrollByTimestamp,
has_enroll_by: true,
is_active: true,
weeks_to_complete: 60,
end: dayjs().add(1, 'year').toISOString(),
Expand All @@ -131,7 +134,8 @@ const execEdData = {
start: futureStartDate,
upgrade_deadline: 1892678399,
pacing_type: 'instructor_paced',
enroll_by: 1892678399,
enroll_by: enrollByTimestamp,
has_enroll_by: true,
is_active: true,
weeks_to_complete: 60,
end: dayjs().add(1, 'year').toISOString(),
Expand Down Expand Up @@ -287,7 +291,7 @@ describe('Course card works as expected', () => {
});

test('executive education card renders', () => {
const enrollByDate = getNormalizedEnrollByDate({ enrollBy: dayjs('Dec 22, 2029') });
const enrollByDate = getNormalizedEnrollByDate({ enrollBy: dayjs.unix(enrollByTimestamp).toISOString() });
const formattedEnrollBy = dayjs(enrollByDate).format(SHORT_MONTH_DATE_FORMAT);
renderWithRouter(<CourseCardWrapper {...execEdProps} />);
expect(screen.queryByText('$999')).toBeInTheDocument();
Expand Down
3 changes: 3 additions & 0 deletions src/components/learner-credit-management/data/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -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;

//
export const LATE_ENROLLMENTS_BUFFER_DAYS = 30;

// Query Key factory for the learner credit management module, intended to be used with `@tanstack/react-query`.
// Inspired by https://tkdodo.eu/blog/effective-react-query-keys#use-query-key-factories.
export const learnerCreditManagementQueryKeys = {
Expand Down
43 changes: 29 additions & 14 deletions src/components/learner-credit-management/data/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import {
ASSIGNMENT_ENROLLMENT_DEADLINE,
COURSE_PACING_MAP,
DAYS_UNTIL_ASSIGNMENT_ALLOCATION_EXPIRATION,
LATE_ENROLLMENTS_BUFFER_DAYS,
LOW_REMAINING_BALANCE_PERCENT_THRESHOLD,
MAX_ALLOWABLE_REFUND_THRESHOLD_DAYS,
NO_BALANCE_REMAINING_DOLLAR_THRESHOLD,
Expand Down Expand Up @@ -565,9 +566,16 @@ export const isLmsBudget = (
export const hasCourseStarted = (start) => dayjs(start).isBefore(dayjs());

/**
* Returns assignable course runs within the threshold of within the subsidies expiration date
* offset by the DAYS_UNTIL_ASSIGNMENT_ALLOCATION_EXPIRATION constant. It sorts it from the soonest expiring
* enroll-by date and the enroll-by date and upgrade deadline has been normalized to ISO format.
* Filters assignable course runs based on the following criteria:
* - If hasEnrollBy, we return the soonest of two dates: The subsidy expiration date - refund threshold OR today
* offset by the 90-day allocation threshold for an assignment denoted as isEligibleForEnrollment
* - If isLateRedemptionEnabled, we consider only the isLateEnrollmentEligible field returned by Algolia for
* each run.
*
* Based on the above criteria, if isLateRedemptionAllowed is false, filter on if the course run isActive AND
* isEligibleForEnrollment
*
* Furthermore, we return assignable course runs sorted by the enrollBy date (soonest to latest)
*
* @param courseRuns
* @param subsidyExpirationDatetime
Expand All @@ -577,20 +585,27 @@ export const hasCourseStarted = (start) => dayjs(start).isBefore(dayjs());
export const getAssignableCourseRuns = ({ courseRuns, subsidyExpirationDatetime, isLateRedemptionAllowed }) => {
const clonedCourseRuns = courseRuns.map(courseRun => ({
...courseRun,
enrollBy: dayjs.unix(courseRun.enrollBy).toISOString(),
enrollBy: courseRun.hasEnrollBy ? dayjs.unix(courseRun.enrollBy).toISOString() : null,
upgradeDeadline: dayjs.unix(courseRun.upgradeDeadline).toISOString(),
}));
const assignableCourseRunsFilter = ({ enrollBy, isActive }) => {
const enrollByDateThreshold = dayjs(enrollBy).isBefore(
Math.max(
dayjs(subsidyExpirationDatetime).subtract(MAX_ALLOWABLE_REFUND_THRESHOLD_DAYS, 'days').toDate(),
dayjs().add(DAYS_UNTIL_ASSIGNMENT_ALLOCATION_EXPIRATION, 'days').toDate(),
),
);
if (isLateRedemptionAllowed) {
return enrollByDateThreshold;
const assignableCourseRunsFilter = ({
enrollBy, isActive, hasEnrollBy = false, isLateEnrollmentEligible = false,
}) => {
let isEligibleForEnrollment = true;
if (hasEnrollBy) {
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(),
),
);
}
if (hasCourseStarted(enrollBy) && isLateRedemptionAllowed) {
const lateEnrollmentCutoff = dayjs().subtract(LATE_ENROLLMENTS_BUFFER_DAYS, 'days');
isEligibleForEnrollment = dayjs(enrollBy).isAfter(lateEnrollmentCutoff);

Check warning on line 605 in src/components/learner-credit-management/data/utils.js

View check run for this annotation

Codecov / codecov/patch

src/components/learner-credit-management/data/utils.js#L604-L605

Added lines #L604 - L605 were not covered by tests
return isLateEnrollmentEligible && isEligibleForEnrollment;
}
return isActive && enrollByDateThreshold;
return isActive && isEligibleForEnrollment;
};
const assignableCourseRuns = clonedCourseRuns.filter(assignableCourseRunsFilter);
const sortedAssignableCourseRuns = assignableCourseRuns.sort((a, b) => a.enrollBy - b.enrollBy);
Expand Down

0 comments on commit 9a899a3

Please sign in to comment.