From b615886bc023e10c697bc3d7dc71eda3dba7532f Mon Sep 17 00:00:00 2001 From: Cyril Nxumalo Date: Tue, 7 May 2024 16:04:13 +0200 Subject: [PATCH] feat: Retired workflow on the list policy screens --- .../learner-credit-management/BudgetCard.jsx | 3 + .../SubBudgetCard.jsx | 87 +++++++++++-------- .../learner-credit-management/data/utils.js | 8 +- .../tests/BudgetCard.test.jsx | 68 +++++++++++++++ 4 files changed, 126 insertions(+), 40 deletions(-) diff --git a/src/components/learner-credit-management/BudgetCard.jsx b/src/components/learner-credit-management/BudgetCard.jsx index 5eb4f2d678..fb9807701c 100644 --- a/src/components/learner-credit-management/BudgetCard.jsx +++ b/src/components/learner-credit-management/BudgetCard.jsx @@ -26,6 +26,7 @@ const BudgetCard = ({ original }) => { id, isAssignable, isRetired, + retiredAt, name, source, start, @@ -51,6 +52,7 @@ const BudgetCard = ({ original }) => { enterpriseSlug={enterpriseSlug} isAssignable={isAssignable} isRetired={isRetired} + retiredAt={retiredAt} /> ); } @@ -107,6 +109,7 @@ BudgetCard.propTypes = { }), isAssignable: PropTypes.bool, isRetired: PropTypes.bool, + retiredAt: PropTypes.string, enterpriseUUID: PropTypes.string.isRequired, enterpriseSlug: PropTypes.string.isRequired, status: PropTypes.string, diff --git a/src/components/learner-credit-management/SubBudgetCard.jsx b/src/components/learner-credit-management/SubBudgetCard.jsx index 6f4a4fc3ef..1e8864e0f9 100644 --- a/src/components/learner-credit-management/SubBudgetCard.jsx +++ b/src/components/learner-credit-management/SubBudgetCard.jsx @@ -65,6 +65,7 @@ const BaseSubBudgetCard = ({ isLoading, isAssignable, isRetired, + retiredAt, }) => { const { isFetching: isFetchingBudgets } = useEnterpriseBudgets({ enablePortalLearnerCreditManagementScreen, @@ -75,15 +76,26 @@ const BaseSubBudgetCard = ({ startDateStr: start, endDateStr: end, isBudgetRetired: isRetired, + retiredDateStr: retiredAt, }); const formattedDate = budgetLabel?.date ? dayjs(budgetLabel?.date).format('MMMM D, YYYY') : undefined; + const isBudgetActiveOrRetired = () => { + const { status } = budgetLabel; + + return ( + status === BUDGET_STATUSES.active + || status === BUDGET_STATUSES.expiring + || status === BUDGET_STATUSES.retired + ); + }; + const renderActions = (budgetId) => ( @@ -93,7 +105,7 @@ const BaseSubBudgetCard = ({ const subtitle = ( {budgetLabel.status} - {(budgetLabel.term && formattedDate) && ( + {budgetLabel.term && formattedDate && ( {budgetLabel.term} {formattedDate} @@ -101,51 +113,54 @@ const BaseSubBudgetCard = ({ ); + const showActions = budgetLabel.status !== BUDGET_STATUSES.scheduled; + const showBottomMargin = !isBudgetActiveOrRetired; + return ( {budgetType}} subtitle={{subtitle}} - actions={ - budgetLabel.status !== BUDGET_STATUSES.scheduled - ? renderActions(budgetId) - : undefined - } - className={classNames('align-items-center', { - 'mb-4.5': budgetLabel.status !== BUDGET_STATUSES.active && budgetLabel.status !== BUDGET_STATUSES.expiring, - })} + actions={showActions ? renderActions(budgetId) : undefined} + className={classNames('align-items-center', { 'mb-4.5': showBottomMargin })} /> ); }; - const renderCardSection = () => ( - Balance} - muted - > - - -
Available
- - {isFetchingBudgets ? : formatPrice(available)} - - - {isAssignable && ( + const renderCardSection = () => { + if (!isBudgetActiveOrRetired) { + return null; + } + + return ( + Balance} + muted + > + + +
Available
+ + {isFetchingBudgets ? : formatPrice(available)} + + + {isAssignable && ( + +
Assigned
+ + {isFetchingBudgets ? : formatPrice(pending)} + + + )} -
Assigned
+
Spent
- {isFetchingBudgets ? : formatPrice(pending)} + {isFetchingBudgets ? : formatPrice(spent)} - )} - -
Spent
- - {isFetchingBudgets ? : formatPrice(spent)} - - -
- ); +
+ ); + }; return ( {renderCardHeader(displayName || 'Overview', id)} - {(budgetLabel.status === BUDGET_STATUSES.active || budgetLabel.status === BUDGET_STATUSES.expiring) - && renderCardSection()} + {renderCardSection()} @@ -178,6 +192,7 @@ BaseSubBudgetCard.propTypes = { displayName: PropTypes.string, isAssignable: PropTypes.bool, isRetired: PropTypes.bool, + retiredAt: PropTypes.string, }; BaseSubBudgetCard.defaultProps = { diff --git a/src/components/learner-credit-management/data/utils.js b/src/components/learner-credit-management/data/utils.js index 5b78ddc73a..7aaac0a813 100644 --- a/src/components/learner-credit-management/data/utils.js +++ b/src/components/learner-credit-management/data/utils.js @@ -155,6 +155,7 @@ export const getBudgetStatus = ({ endDateStr, isBudgetRetired, currentDate = new Date(), + retiredDateStr = null, }) => { const startDate = new Date(startDateStr); const endDate = new Date(endDateStr); @@ -163,10 +164,9 @@ export const getBudgetStatus = ({ if (isBudgetRetired) { return { status: BUDGET_STATUSES.retired, - badgeVariant: 'info', - // no term or date for retired budgets - term: null, - date: null, + badgeVariant: 'light', + term: 'Retired', + date: retiredDateStr, }; } diff --git a/src/components/learner-credit-management/tests/BudgetCard.test.jsx b/src/components/learner-credit-management/tests/BudgetCard.test.jsx index 43687867db..c74b567821 100644 --- a/src/components/learner-credit-management/tests/BudgetCard.test.jsx +++ b/src/components/learner-credit-management/tests/BudgetCard.test.jsx @@ -547,4 +547,72 @@ describe('', () => { expect(screen.getByText('Spent')).toBeInTheDocument(); expect(screen.getByText(formatPrice(mockBudgetAggregates.spent))).toBeInTheDocument(); }); + + it.each([ + { isAssignableBudget: false }, + { isAssignableBudget: true }, + ])('displays correctly for a retired Policy (enterprise-access) (%s)', ({ isAssignableBudget }) => { + const mockBudgetAggregates = { + total: 5000, + spent: 200, + pending: isAssignableBudget ? 100 : undefined, + available: isAssignableBudget ? 4700 : 4800, + }; + + // Mock budget data + const mockBudget = { + id: mockBudgetUuid, + name: mockBudgetDisplayName, + start: '2022-01-01', + end: '3023-01-01', + source: BUDGET_TYPES.policy, + aggregates: { + available: mockBudgetAggregates.available, + pending: mockBudgetAggregates.pending, + spent: mockBudgetAggregates.spent, + }, + isAssignable: isAssignableBudget, + enterpriseSlug, + enterpriseUUID, + isRetired: true, + retiredAt: '2022-01-01', + }; + + useSubsidySummaryAnalyticsApi.mockReturnValue({ + isLoading: false, + subsidySummary: undefined, + }); + + render(); + + // Assertions for budget card display + expect(screen.getByText(mockBudgetDisplayName)).toBeInTheDocument(); + expect(screen.queryByText('Executive Education')).not.toBeInTheDocument(); + + const formattedString = `Retired ${dayjs(mockBudget.retiredAt).format('MMMM D, YYYY')}`; + const elementsWithTestId = screen.getAllByTestId('budget-date'); + const firstElementWithTestId = elementsWithTestId[0]; + expect(firstElementWithTestId).toHaveTextContent(formattedString); + + // Verify 'View budget' CTA + const viewBudgetCTA = screen.getByText('View budget', { selector: 'a' }); + expect(viewBudgetCTA).toBeInTheDocument(); // Ensure 'View budget' CTA is present + expect(viewBudgetCTA).toHaveAttribute( + 'href', + `/${enterpriseSlug}/admin/learner-credit/${mockBudgetUuid}`, + ); + + // Assertions for aggregates display + expect(screen.getByText('Balance')).toBeInTheDocument(); + expect(screen.getByText('Available')).toBeInTheDocument(); + expect(screen.getByText(formatPrice(mockBudgetAggregates.available))).toBeInTheDocument(); + if (isAssignableBudget) { + expect(screen.getByText('Assigned')).toBeInTheDocument(); + expect(screen.getByText(formatPrice(mockBudgetAggregates.pending))).toBeInTheDocument(); + } else { + expect(screen.queryByText('Assigned')).not.toBeInTheDocument(); + } + expect(screen.getByText('Spent')).toBeInTheDocument(); + expect(screen.getByText(formatPrice(mockBudgetAggregates.spent))).toBeInTheDocument(); + }); });