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 9cd682c6b4..fa5e7f1604 100644 --- a/src/components/learner-credit-management/SubBudgetCard.jsx +++ b/src/components/learner-credit-management/SubBudgetCard.jsx @@ -68,6 +68,7 @@ const BaseSubBudgetCard = ({ isLoading, isAssignable, isRetired, + retiredAt, }) => { const { isFetching: isFetchingBudgets } = useEnterpriseBudgets({ enablePortalLearnerCreditManagementScreen, @@ -79,6 +80,7 @@ const BaseSubBudgetCard = ({ startDateStr: start, endDateStr: end, isBudgetRetired: isRetired, + retiredDateStr: retiredAt, }); const formattedDate = budgetLabel?.date ? intl.formatDate( dayjs(budgetLabel?.date).toDate(), @@ -89,6 +91,16 @@ const BaseSubBudgetCard = ({ }, ) : undefined; + const hasBudgetAggregatesSection = () => { + const { status } = budgetLabel; + + return ( + status === BUDGET_STATUSES.active + || status === BUDGET_STATUSES.expiring + || status === BUDGET_STATUSES.retired + ); + }; + const renderActions = (budgetId) => ( ); @@ -116,77 +136,83 @@ const BaseSubBudgetCard = ({ ); + const showActions = budgetLabel.status !== BUDGET_STATUSES.scheduled; + 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': !hasBudgetAggregatesSection })} /> ); }; - const renderCardSection = () => ( - - - -)} - muted - > - - -
+ const renderCardSection = () => { + if (!hasBudgetAggregatesSection) { + return null; + } + + return ( + -
- - {isFetchingBudgets ? : formatPrice(available)} - - - {isAssignable && ( - -
+ + )} + muted + > + + {!isRetired && ( + <> + +
+ +
+ + {isFetchingBudgets ? : formatPrice(available)} + + + {isAssignable && ( + +
+ +
+ + {isFetchingBudgets ? : formatPrice(pending)} + + + )} + + )} + +
- - {isFetchingBudgets ? : formatPrice(pending)} + + {isFetchingBudgets ? : formatPrice(spent)} - )} - -
- -
- - {isFetchingBudgets ? : formatPrice(spent)} - - - - ); + + ); + }; return ( {renderCardHeader(displayName || 'Overview', id)} - {(budgetLabel.status === BUDGET_STATUSES.active || budgetLabel.status === BUDGET_STATUSES.expiring) - && renderCardSection()} + {renderCardSection()} @@ -219,6 +244,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 2fc358df5a..65e86ec30e 100644 --- a/src/components/learner-credit-management/data/utils.js +++ b/src/components/learner-credit-management/data/utils.js @@ -163,6 +163,7 @@ export const getBudgetStatus = ({ endDateStr, isBudgetRetired, currentDate = new Date(), + retiredDateStr = null, }) => { const startDate = new Date(startDateStr); const endDate = new Date(endDateStr); @@ -171,10 +172,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, }; } @@ -532,6 +532,12 @@ export const getTranslatedBudgetTerm = (intl, term) => { defaultMessage: 'Expired', description: 'Term for when a budget has expired', }); + case 'Retired': + return intl.formatMessage({ + id: 'lcm.budgets.budget.card.term.retired', + defaultMessage: 'Retired', + description: 'Term for when a budget has retired', + }); default: return ''; } diff --git a/src/components/learner-credit-management/tests/BudgetCard.test.jsx b/src/components/learner-credit-management/tests/BudgetCard.test.jsx index 43687867db..e3437c45db 100644 --- a/src/components/learner-credit-management/tests/BudgetCard.test.jsx +++ b/src/components/learner-credit-management/tests/BudgetCard.test.jsx @@ -7,6 +7,7 @@ import dayjs from 'dayjs'; import { screen, render, + within, } from '@testing-library/react'; import '@testing-library/jest-dom/extend-expect'; @@ -547,4 +548,64 @@ describe('', () => { expect(screen.getByText('Spent')).toBeInTheDocument(); expect(screen.getByText(formatPrice(mockBudgetAggregates.spent))).toBeInTheDocument(); }); + + it('displays correctly for a retired Policy (enterprise-access) (%s)', () => { + const mockBudgetAggregates = { + total: 5000, + spent: 200, + pending: undefined, + available: 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: false, + 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 history', { selector: 'a' }); + expect(viewBudgetCTA).toBeInTheDocument(); // Ensure 'View budget' CTA is present + expect(viewBudgetCTA).toHaveAttribute( + 'href', + `/${enterpriseSlug}/admin/learner-credit/${mockBudgetUuid}`, + ); + + const balanceDetailSection = screen.getByTestId('balance-detail-section'); + + // Assertions for aggregates display + expect(within(balanceDetailSection).queryByText('Balance')).not.toBeInTheDocument(); + expect(within(balanceDetailSection).queryByText('Available')).not.toBeInTheDocument(); + expect(within(balanceDetailSection).getByText('Spent')).toBeInTheDocument(); + expect(within(balanceDetailSection).getByText(formatPrice(mockBudgetAggregates.spent))).toBeInTheDocument(); + }); });