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: UI updates expired workflow #1264

Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -318,7 +318,7 @@ describe('useEnterpriseBudgets', () => {
);
});

it.each('should set `canManageLearnerCredit` to false if no budgets are found', async () => {
it('should set `canManageLearnerCredit` to false if no budgets are found', async () => {
fetchEnterpriseOffersSpy.mockResolvedValue({
data: {
results: [],
Expand Down
Original file line number Diff line number Diff line change
@@ -1,13 +1,24 @@
import React from 'react';
import PropTypes from 'prop-types';
import { formatPrice, useBudgetId, useSubsidyAccessPolicy } from './data';
import { useIntl } from '@edx/frontend-platform/i18n';
import {
formatPrice, getBudgetStatus, useBudgetId, useSubsidyAccessPolicy,
} from './data';
import { BUDGET_STATUSES } from '../EnterpriseApp/data/constants';

const AssignmentAmountTableCell = ({ row }) => {
const intl = useIntl();
const { subsidyAccessPolicyId } = useBudgetId();
const { data: subsidyAccessPolicy } = useSubsidyAccessPolicy(subsidyAccessPolicyId);
const isRetired = !!subsidyAccessPolicy?.retired;
const { status } = getBudgetStatus({
intl,
startDateStr: subsidyAccessPolicy.subsidyActiveDatetime,
endDateStr: subsidyAccessPolicy.subsidyExpirationDatetime,
isBudgetRetired: subsidyAccessPolicy.retired,
});
const shouldStrikeoutPrice = [BUDGET_STATUSES.expired, BUDGET_STATUSES.retired].includes(status);

if (isRetired) {
if (shouldStrikeoutPrice) {
return (
<strike>-{formatPrice(row.original.contentQuantity / 100)}</strike>
);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { Chip } from '@openedx/paragon';
import PropTypes from 'prop-types';
import { sendEnterpriseTrackEvent } from '@edx/frontend-enterprise-utils';
import { connect } from 'react-redux';
import { useIntl } from '@edx/frontend-platform/i18n';
import FailedBadEmail from './assignments-status-chips/FailedBadEmail';
import FailedCancellation from './assignments-status-chips/FailedCancellation';
import FailedRedemption from './assignments-status-chips/FailedRedemption';
Expand All @@ -10,10 +11,16 @@ import FailedSystem from './assignments-status-chips/FailedSystem';
import NotifyingLearner from './assignments-status-chips/NotifyingLearner';
import WaitingForLearner from './assignments-status-chips/WaitingForLearner';
import { capitalizeFirstLetter } from '../../utils';
import { useBudgetId, useSubsidyAccessPolicy } from './data';
import {
getBudgetStatus,
useBudgetId,
useSubsidyAccessPolicy,
} from './data';
import IncompleteAssignment from './assignments-status-chips/IncompleteAssignment';
import { BUDGET_STATUSES } from '../EnterpriseApp/data/constants';

const AssignmentStatusTableCell = ({ enterpriseId, row }) => {
const intl = useIntl();
const { original } = row;
const {
learnerEmail,
Expand All @@ -22,10 +29,16 @@ const AssignmentStatusTableCell = ({ enterpriseId, row }) => {
} = original;
const { subsidyAccessPolicyId } = useBudgetId();
const { data: subsidyAccessPolicy } = useSubsidyAccessPolicy(subsidyAccessPolicyId);
const { status } = getBudgetStatus({
intl,
startDateStr: subsidyAccessPolicy.subsidyActiveDatetime,
endDateStr: subsidyAccessPolicy.subsidyExpirationDatetime,
isBudgetRetired: subsidyAccessPolicy.retired,
});
const {
retired: isRetired, subsidyUuid, assignmentConfiguration, isSubsidyActive, isAssignable, catalogUuid, aggregates,
subsidyUuid, assignmentConfiguration, isSubsidyActive, isAssignable, catalogUuid, aggregates,
} = subsidyAccessPolicy;

const budgetStatusesWithIncompleteAssignments = [BUDGET_STATUSES.expired, BUDGET_STATUSES.retired];
const sharedTrackEventMetadata = {
learnerState,
subsidyUuid,
Expand Down Expand Up @@ -72,7 +85,7 @@ const AssignmentStatusTableCell = ({ enterpriseId, row }) => {
}

// Always display "Incomplete assignment" status chip for retired budgets
if (isRetired) {
if (budgetStatusesWithIncompleteAssignments.includes(status)) {
return (
<IncompleteAssignment trackEvent={sendGenericTrackEvent} />
);
Expand Down
28 changes: 12 additions & 16 deletions src/components/learner-credit-management/BudgetAssignmentsTable.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,13 @@ import AssignmentRowActionTableCell from './AssignmentRowActionTableCell';
import AssignmentTableRemindAction from './AssignmentTableRemind';
import AssignmentTableCancelAction from './AssignmentTableCancel';
import {
DEFAULT_PAGE, PAGE_SIZE, useBudgetId, useSubsidyAccessPolicy,
DEFAULT_PAGE, PAGE_SIZE,
} from './data';
import AssignmentRecentActionTableCell from './AssignmentRecentActionTableCell';
import AssignmentsTableRefreshAction from './AssignmentsTableRefreshAction';
import AssignmentEnrollByDateCell from './AssignmentEnrollByDateCell';
import AssignmentEnrollByDateHeader from './AssignmentEnrollByDateHeader';
import { BUDGET_STATUSES } from '../EnterpriseApp/data/constants';

const FilterStatus = (rest) => <DataTable.FilterStatus showFilteredFields={false} {...rest} />;

Expand Down Expand Up @@ -45,6 +46,7 @@ const BudgetAssignmentsTable = ({
isLoading,
tableData,
fetchTableData,
status,
}) => {
const intl = useIntl();
const statusFilterChoices = tableData.learnerStateCounts
Expand All @@ -54,13 +56,10 @@ const BudgetAssignmentsTable = ({
number: count,
value: learnerState,
}));

const { subsidyAccessPolicyId } = useBudgetId();
const { data: subsidyAccessPolicy } = useSubsidyAccessPolicy(subsidyAccessPolicyId);
const isRetired = !!subsidyAccessPolicy?.retired;
const isRetiredOrExpired = [BUDGET_STATUSES.retired, BUDGET_STATUSES.expired].includes(status);

const budgetAssignmentsTableData = (() => {
if (isRetired) {
if (isRetiredOrExpired) {
return {
tableActions: [],
additionalColumns: [],
Expand All @@ -82,7 +81,7 @@ const BudgetAssignmentsTable = ({
return (
<DataTable
isSortable
isSelectable={!isRetired}
isSelectable={!isRetiredOrExpired}
manualSortBy
isPaginated
manualPagination
Expand All @@ -95,8 +94,7 @@ const BudgetAssignmentsTable = ({
SelectionStatusComponent={DataTable.ControlledSelectionStatus}
columns={[
{
Header:
intl.formatMessage({
Header: intl.formatMessage({
id: 'lcm.budget.detail.page.assignments.table.columns.assignment.details',
defaultMessage: 'Assignment details',
description: 'Column header for the assignment details column in the assignments table',
Expand All @@ -106,8 +104,7 @@ const BudgetAssignmentsTable = ({
disableSortBy: true,
},
{
Header:
intl.formatMessage({
Header: intl.formatMessage({
id: 'lcm.budget.detail.page.assignments.table.columns.amount',
defaultMessage: 'Amount',
description: 'Column header for the amount column in the assignments table',
Expand All @@ -117,22 +114,20 @@ const BudgetAssignmentsTable = ({
disableFilters: true,
},
{
Header:
intl.formatMessage({
Header: intl.formatMessage({
id: 'lcm.budget.detail.page.assignments.table.columns.status',
defaultMessage: 'Status',
description: 'Column header for the status column in the assignments table',
}),
accessor: 'learnerState',
Cell: AssignmentStatusTableCell,
disableFilters: isRetired,
disableFilters: isRetiredOrExpired,
Filter: CheckboxFilter,
filter: 'includesValue',
filterChoices: statusFilterChoices,
},
{
Header:
intl.formatMessage({
Header: intl.formatMessage({
id: 'lcm.budget.detail.page.assignments.table.columns.recent.action',
defaultMessage: 'Recent action',
description: 'Column header for the recent action column in the assignments table',
Expand Down Expand Up @@ -188,6 +183,7 @@ BudgetAssignmentsTable.propTypes = {
numPages: PropTypes.number.isRequired,
}).isRequired,
fetchTableData: PropTypes.func.isRequired,
status: PropTypes.string.isRequired,
};

export default BudgetAssignmentsTable;
3 changes: 1 addition & 2 deletions src/components/learner-credit-management/BudgetCard.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -61,8 +61,8 @@ const BudgetCard = ({ original }) => {
if (source === BUDGET_TYPES.ecommerce) {
return (
<SubBudgetCard
isLoading={isLoadingSubsidySummaryAnalyticsApi}
id={subsidySummaryAnalyticsApi?.offerId}
isLoading={isLoadingSubsidySummaryAnalyticsApi}
start={start}
end={end}
available={subsidySummaryAnalyticsApi?.remainingFunds}
Expand Down Expand Up @@ -112,7 +112,6 @@ BudgetCard.propTypes = {
retiredAt: PropTypes.string,
enterpriseUUID: PropTypes.string.isRequired,
enterpriseSlug: PropTypes.string.isRequired,
status: PropTypes.string,
}).isRequired,
};

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,13 +5,19 @@
import { getConfig } from '@edx/frontend-platform/config';
import { useNavigate, useLocation } from 'react-router-dom';

import { FormattedMessage } from '@edx/frontend-platform/i18n';
import { FormattedMessage, useIntl } from '@edx/frontend-platform/i18n';
import BudgetAssignmentsTable from './BudgetAssignmentsTable';
import AssignMoreCoursesEmptyStateMinimal from './AssignMoreCoursesEmptyStateMinimal';
import { useBudgetContentAssignments, useBudgetId, useSubsidyAccessPolicy } from './data';
import {
getBudgetStatus,
useBudgetContentAssignments,
useBudgetId,
useSubsidyAccessPolicy,
} from './data';
import { BUDGET_STATUSES } from '../EnterpriseApp/data/constants';

const BudgetDetailAssignmentsHeader = ({
isRetired,
status,
}) => {
const assignedHeadingRef = useRef();
const navigate = useNavigate();
Expand All @@ -28,7 +34,7 @@
}
}, [navigate, location, locationState]);

if (isRetired) {
if ([BUDGET_STATUSES.retired, BUDGET_STATUSES.expired].includes(status)) {
return (
<>
<h3 className="mb-3" ref={assignedHeadingRef}>
Expand All @@ -38,13 +44,24 @@
description="Heading for the incomplete assignments section on the budget detail page"
/>
</h3>
<p className="small mb-4 text-info-900">
<FormattedMessage
id="lcm.budget.detail.page.incomplete.assignments.description"
defaultMessage="The assignments below were made before the budget was retired and were never completed by the learner."
description="Description for the incomplete assignments section on the budget detail page. Includes a link to learn more."
/>
</p>
{status === BUDGET_STATUSES.retired && (
<p className="small mb-4 text-info-900">
<FormattedMessage
id="lcm.budget.detail.page.incomplete.assignments.description.retired"
defaultMessage="The assignments below were made before the budget was retired and were never completed by the learner."
description="Description for the incomplete assignments section on the budget detail page."
/>
</p>
)}
{status === BUDGET_STATUSES.expired && (
<p className="small mb-4 text-info-900">

Check warning on line 57 in src/components/learner-credit-management/BudgetDetailAssignments.jsx

View check run for this annotation

Codecov / codecov/patch

src/components/learner-credit-management/BudgetDetailAssignments.jsx#L57

Added line #L57 was not covered by tests
<FormattedMessage
id="lcm.budget.detail.page.incomplete.assignments.description.expired"
defaultMessage="The assignments below were made before the budget was expired and were never completed by the learner."
description="Description for the incomplete assignments section on the budget detail page."
/>
</p>
)}
</>
);
}
Expand Down Expand Up @@ -82,7 +99,7 @@
};

BudgetDetailAssignmentsHeader.propTypes = {
isRetired: PropTypes.bool.isRequired,
status: PropTypes.string.isRequired,
};

const BudgetDetailAssignments = ({
Expand All @@ -91,11 +108,10 @@
enterpriseFeatures,
enterpriseId,
}) => {
const intl = useIntl();
const { subsidyAccessPolicyId } = useBudgetId();
const { data: subsidyAccessPolicy } = useSubsidyAccessPolicy(subsidyAccessPolicyId);

const isAssignableBudget = !!subsidyAccessPolicy?.isAssignable;
const isRetired = !!subsidyAccessPolicy?.retired;
const assignmentConfigurationUUID = subsidyAccessPolicy?.assignmentConfiguration?.uuid;
const isTopDownAssignmentEnabled = enterpriseFeatures.topDownAssignmentRealTimeLcm;
const {
Expand All @@ -107,6 +123,12 @@
assignmentConfigurationUUID,
enterpriseId,
});
const { status } = getBudgetStatus({
intl,
startDateStr: subsidyAccessPolicy.subsidyActiveDatetime,
endDateStr: subsidyAccessPolicy.subsidyExpirationDatetime,
isBudgetRetired: subsidyAccessPolicy.retired,
});

if (!isTopDownAssignmentEnabled || !isAssignableBudget) {
return null;
Expand All @@ -120,11 +142,12 @@

return (
<section className="budget-detail-assignments">
<BudgetDetailAssignmentsHeader isRetired={isRetired} />
<BudgetDetailAssignmentsHeader status={status} />
<BudgetAssignmentsTable
isLoading={isLoading}
tableData={contentAssignments}
fetchTableData={fetchContentAssignments}
status={status}
/>
</section>
);
Expand Down
Loading
Loading