Skip to content

Commit

Permalink
refactor: Updates logic for start date threshold
Browse files Browse the repository at this point in the history
  • Loading branch information
brobro10000 committed Sep 12, 2024
1 parent ddab547 commit 7ec4892
Show file tree
Hide file tree
Showing 10 changed files with 81 additions and 46 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -18,10 +18,9 @@ import {
useSubsidyAccessPolicy,
useEnterpriseCustomer,
useEnterpriseGroup,
isLmsBudget,
isLmsBudget, LEARNER_CREDIT_ROUTE,
} from './data';
import EVENT_NAMES from '../../eventTracking';
import { LEARNER_CREDIT_ROUTE } from './constants';
import { BUDGET_STATUSES } from '../EnterpriseApp/data/constants';
import BudgetDetail from './BudgetDetail';
import { useEnterpriseBudgets } from '../EnterpriseSubsidiesContext/data/hooks';
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,9 +9,8 @@ import { sendEnterpriseTrackEvent } from '@edx/frontend-enterprise-utils';
import { generatePath, useParams, Link } from 'react-router-dom';

import { FormattedMessage, useIntl } from '@edx/frontend-platform/i18n';
import { formatPrice } from './data';
import { formatPrice, LEARNER_CREDIT_ROUTE } from './data';
import EVENT_NAMES from '../../eventTracking';
import { LEARNER_CREDIT_ROUTE } from './constants';

const BudgetDetailPageOverviewUtilization = ({
budgetId,
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,9 @@ import { defineMessages, useIntl } from '@edx/frontend-platform/i18n';
import PropTypes from 'prop-types';

import dayjs from 'dayjs';
import { setStaleCourseStartDates, hasCourseStarted, SHORT_MONTH_DATE_FORMAT } from '../data';
import {
getNormalizedEnrollByDate, getNormalizedStartDate, hasCourseStarted, SHORT_MONTH_DATE_FORMAT,
} from '../data';

const messages = defineMessages({
importantDates: {
Expand Down Expand Up @@ -47,12 +49,11 @@ AssignmentModalImportantDate.propTypes = {

const AssignmentModalImportantDates = ({ courseRun }) => {
const intl = useIntl();
const enrollByDate = courseRun.enrollBy
? dayjs(courseRun.enrollBy).format(SHORT_MONTH_DATE_FORMAT)
: null;
const courseStartDate = courseRun.start
? setStaleCourseStartDates({ start: courseRun.start })
const normalizedEnrollByDate = getNormalizedEnrollByDate(courseRun);
const enrollByDate = normalizedEnrollByDate
? dayjs(normalizedEnrollByDate).format(SHORT_MONTH_DATE_FORMAT)
: null;
const courseStartDate = getNormalizedStartDate(courseRun);
const courseHasStartedLabel = hasCourseStarted(courseStartDate)
? intl.formatMessage(messages.courseStarted)
: intl.formatMessage(messages.courseStarts);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,14 @@ import { FormattedMessage, useIntl } from '@edx/frontend-platform/i18n';
import AssignmentModalContent from './AssignmentModalContent';
import EnterpriseAccessApiService from '../../../data/services/EnterpriseAccessApiService';
import {
getAssignableCourseRuns,
getAssignableCourseRuns, LEARNER_CREDIT_ROUTE,
learnerCreditManagementQueryKeys,
useBudgetId,
useSubsidyAccessPolicy,
} from '../data';
import CreateAllocationErrorAlertModals from './CreateAllocationErrorAlertModals';
import { BudgetDetailPageContext } from '../BudgetDetailPageWrapper';
import EVENT_NAMES from '../../../eventTracking';
import { LEARNER_CREDIT_ROUTE } from '../constants';
import NewAssignmentModalDropdown from './NewAssignmentModalDropdown';

const useAllocateContentAssignments = () => useMutation({
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,8 @@ import PropTypes from 'prop-types';
import { defineMessages, useIntl } from '@edx/frontend-platform/i18n';
import { useState } from 'react';
import {
setStaleCourseStartDates,
getNormalizedEnrollByDate,
getNormalizedStartDate,
SHORT_MONTH_DATE_FORMAT,
} from '../data';

Expand Down Expand Up @@ -32,6 +33,7 @@ const NewAssignmentModalDropdown = ({
}
return 'text-muted';
};
const startLabel = ({ start }) => (dayjs(start).isBefore(dayjs()) ? 'Started' : 'Starts');
return (
<Dropdown id={courseKey}>
<Dropdown.Toggle variant="primary" id="assign-by-course-runs-dropdown">
Expand All @@ -50,9 +52,9 @@ const NewAssignmentModalDropdown = ({
onMouseUp={() => setClickedDropdownItem(null)}
>
<Stack>
Enroll by {dayjs(courseRun.enrollBy).format(SHORT_MONTH_DATE_FORMAT)}
Enroll by {dayjs(getNormalizedEnrollByDate(courseRun)).format(SHORT_MONTH_DATE_FORMAT)}
<span className={`small ${getDropdownItemClassName(courseRun)}`}>
Starts {dayjs(setStaleCourseStartDates({ start: courseRun.start })).format(SHORT_MONTH_DATE_FORMAT)}
{startLabel(courseRun)} {dayjs(getNormalizedStartDate(courseRun)).format(SHORT_MONTH_DATE_FORMAT)}
</span>
</Stack>
</Dropdown.Item>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,8 +3,8 @@ import { AppContext } from '@edx/frontend-platform/react';
import cardFallbackImg from '@edx/brand/paragon/images/card-imagecap-fallback.png';

import { defineMessages, useIntl } from '@edx/frontend-platform/i18n';
import CARD_TEXT from '../../constants';
import {
CARD_TEXT,
getAssignableCourseRuns,
EXEC_ED_COURSE_TYPE,
formatDate,
Expand Down
20 changes: 0 additions & 20 deletions src/components/learner-credit-management/constants.js

This file was deleted.

27 changes: 27 additions & 0 deletions src/components/learner-credit-management/data/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,12 @@ export const API_FIELDS_BY_TABLE_COLUMN_ACCESSOR = {
courseListPrice: 'course_list_price',
};

// Course pace text
export const COURSE_PACING_MAP = {
SELF_PACED: 'self_paced',
INSTRUCTOR_PACED: 'instructor_paced',
};

// Percentage where messaging (e.g., Alert) on low remaining balance will begin appearing
export const LOW_REMAINING_BALANCE_PERCENT_THRESHOLD = 0.75;

Expand All @@ -46,6 +52,24 @@ export const BUDGET_DETAIL_TAB_LABELS = {
[BUDGET_DETAIL_MEMBERS_TAB]: 'Members',
};

// Card text for used in useCourseCardMetadata
export const CARD_TEXT = {
BADGE: {
course: 'Course',
execEd: 'Executive Education',
},
BUTTON_ACTION: {
viewCourse: 'View course',
assign: 'Assign',
},
ENROLLMENT: {
text: 'Learner must enroll by',
},
PRICE: {
subText: 'Per learner price',
},
};

// Facet filters
export const LEARNING_TYPE_REFINEMENT = 'learning_type';
export const LANGUAGE_REFINEMENT = 'language';
Expand Down Expand Up @@ -93,3 +117,6 @@ export const learnerCreditManagementQueryKeys = {
budgetGroupLearners: (budgetId) => [...learnerCreditManagementQueryKeys.budget(budgetId), 'group learners'],
enterpriseCustomer: (enterpriseId) => [...learnerCreditManagementQueryKeys.all, 'enterpriseCustomer', enterpriseId],
};

// Route to learner credit
export const LEARNER_CREDIT_ROUTE = '/:enterpriseSlug/admin/:enterpriseAppPage/:budgetId/:activeTabKey';
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
import { useParams, generatePath } from 'react-router-dom';

import useBudgetId from './useBudgetId';
import { LEARNER_CREDIT_ROUTE } from '../../constants';

import { LEARNER_CREDIT_ROUTE } from '../constants';

const usePathToCatalogTab = () => {
const { budgetId } = useBudgetId();
Expand Down
45 changes: 36 additions & 9 deletions src/components/learner-credit-management/data/utils.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@ import {
NO_BALANCE_REMAINING_DOLLAR_THRESHOLD,
ASSIGNMENT_ENROLLMENT_DEADLINE,
DAYS_UNTIL_ASSIGNMENT_ALLOCATION_EXPIRATION,
START_DATE_DEFAULT_TO_TODAY_THRESHOLD_DAYS,
START_DATE_DEFAULT_TO_TODAY_THRESHOLD_DAYS, COURSE_PACING_MAP,
} from './constants';
import { BUDGET_STATUSES } from '../../EnterpriseApp/data/constants';
import EnterpriseAccessApiService from '../../../data/services/EnterpriseAccessApiService';
Expand Down Expand Up @@ -556,15 +556,13 @@ export const isLmsBudget = (

/**
* Determines if the course has already started. Mostly used around text formatting for tense
* Introduces 'jitter' in the form of a 30 second offset to take into account any additional
* formatting that takes place down stream related to setting values to today's date through dayjs()
*
* This should also help with reducing 'flaky' tests.
*
* @param start
* @returns {boolean}
*/
export const hasCourseStarted = (start) => dayjs(start).isBefore(dayjs().subtract(30, 'seconds'));
export const hasCourseStarted = (start) => dayjs(start).isBefore(dayjs());

/**
* Returns assignable course runs within the threshold of within the subsidies expiration date
Expand All @@ -590,6 +588,16 @@ export const getAssignableCourseRuns = ({ courseRuns, subsidyExpirationDatetime
return assignableCourseRuns;
};

export const isCourseSelfPaced = ({ pacingType }) => pacingType === COURSE_PACING_MAP.SELF_PACED;

export const hasTimeToComplete = ({ end, weeksToComplete }) => {
const today = dayjs();
const differenceInWeeks = dayjs(end).diff(today, 'week');
return weeksToComplete <= differenceInWeeks;
};

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

/**
* If the start date of the course is before today offset by the START_DATE_DEFAULT_TO_TODAY_THRESHOLD_DAYS
* then return today's formatted date. Otherwise, pass-through the start date in ISO format.
Expand All @@ -600,12 +608,31 @@ export const getAssignableCourseRuns = ({ courseRuns, subsidyExpirationDatetime
* @param format
* @returns {string}
*/
export const setStaleCourseStartDates = ({ start }) => {
export const getNormalizedStartDate = ({
start, pacingType, end, weeksToComplete,
}) => {
const todayToIso = dayjs().toISOString();
if (!start) {
return dayjs().toISOString();
return todayToIso;
}
const startDateIso = dayjs(start).toISOString();
if (isCourseSelfPaced({ pacingType })) {
if (hasTimeToComplete({ end, weeksToComplete }) || isWithinMinimumStartDateThreshold({ start })) {
// always today's date (incentives enrollment)
return todayToIso;
}
return startDateIso;
}
return startDateIso;
};

export const getNormalizedEnrollByDate = ({ enrollBy }) => {
if (!enrollBy) {
return null;
}
if (dayjs(start).isBefore(dayjs().subtract(START_DATE_DEFAULT_TO_TODAY_THRESHOLD_DAYS, 'days'))) {
return dayjs().toISOString();
const ninetyDayAllocationOffset = dayjs().add(DAYS_UNTIL_ASSIGNMENT_ALLOCATION_EXPIRATION, 'days');
if (dayjs(enrollBy).isAfter(ninetyDayAllocationOffset)) {
return ninetyDayAllocationOffset.toISOString();
}
return dayjs(start).toISOString();
return enrollBy;
};

0 comments on commit 7ec4892

Please sign in to comment.