diff --git a/src/components/learner-credit-management/MultipleBudgetsPage.jsx b/src/components/learner-credit-management/MultipleBudgetsPage.jsx index 95a34f6483..7705ef3b1a 100644 --- a/src/components/learner-credit-management/MultipleBudgetsPage.jsx +++ b/src/components/learner-credit-management/MultipleBudgetsPage.jsx @@ -12,6 +12,7 @@ import { import { connect } from 'react-redux'; import { Helmet } from 'react-helmet'; +import { useIntl, FormattedMessage } from '@edx/frontend-platform/i18n'; import Hero from '../Hero'; import MultipleBudgetsPicker from './MultipleBudgetsPicker'; import { EnterpriseSubsidiesContext } from '../EnterpriseSubsidiesContext'; @@ -19,8 +20,6 @@ import { EnterpriseSubsidiesContext } from '../EnterpriseSubsidiesContext'; import { configuration } from '../../config'; import { useEnterpriseBudgets } from '../EnterpriseSubsidiesContext/data/hooks'; -const PAGE_TITLE = 'Learner Credit Management'; - const MultipleBudgetsPage = ({ enterpriseUUID, enterpriseSlug, @@ -28,6 +27,12 @@ const MultipleBudgetsPage = ({ enterpriseFeatures, enablePortalLearnerCreditManagementScreen, }) => { + const intl = useIntl(); + const PAGE_TITLE = intl.formatMessage({ + id: 'lcm.page.title', + defaultMessage: 'Learner Credit Management', + description: 'Title for the Learner Credit Management page', + }); const { isLoading } = useContext(EnterpriseSubsidiesContext); const { data: budgetsOverview } = useEnterpriseBudgets({ enterpriseId: enterpriseUUID, @@ -43,7 +48,13 @@ const MultipleBudgetsPage = ({ <>

- Loading budgets... + + + ); } @@ -57,17 +68,30 @@ const MultipleBudgetsPage = ({ -

No budgets for your organization

+

+ +

- We were unable to find any budgets for your organization. Please contact - Customer Support if you have questions. +

- Contact support +
diff --git a/src/components/learner-credit-management/MultipleBudgetsPicker.jsx b/src/components/learner-credit-management/MultipleBudgetsPicker.jsx index 0af1fe06a5..8816cddd3b 100644 --- a/src/components/learner-credit-management/MultipleBudgetsPicker.jsx +++ b/src/components/learner-credit-management/MultipleBudgetsPicker.jsx @@ -10,8 +10,9 @@ import { } from '@edx/paragon'; import groupBy from 'lodash/groupBy'; +import { FormattedMessage, useIntl } from '@edx/frontend-platform/i18n'; import BudgetCard from './BudgetCard'; -import { getBudgetStatus, orderBudgets } from './data/utils'; +import { getBudgetStatus, getTranslatedBudgetStatus, orderBudgets } from './data/utils'; const MultipleBudgetsPicker = ({ budgets, @@ -20,7 +21,7 @@ const MultipleBudgetsPicker = ({ enableLearnerPortal, }) => { const orderedBudgets = orderBudgets(budgets); - + const intl = useIntl(); const rows = useMemo( () => orderedBudgets.map(budget => { const budgetLabel = getBudgetStatus({ @@ -49,7 +50,7 @@ const MultipleBudgetsPicker = ({ )); const budgetLabelsByStatus = groupBy(budgetLabels, 'status'); const reducedChoices = Object.keys(budgetLabelsByStatus).map(budgetLabel => ({ - name: budgetLabel, + name: getTranslatedBudgetStatus(intl, budgetLabel), number: budgetLabelsByStatus[budgetLabel].length, value: budgetLabel, })); @@ -57,7 +58,15 @@ const MultipleBudgetsPicker = ({ return ( <> -

Budgets

+ +

+ +

+
( ); const renderCardHeader = (budgetType, budgetId) => { const subtitle = ( - {budgetLabel.status} + {getTranslatedBudgetStatus(intl, budgetLabel.status)} {(budgetLabel.term && formattedDate) && ( - {budgetLabel.term} {formattedDate} + {getTranslatedBudgetTerm(intl, budgetLabel.term)} {formattedDate} )} @@ -119,26 +134,52 @@ const BaseSubBudgetCard = ({ const renderCardSection = () => ( Balance} + title={( +

+ +

+)} muted > -
Available
+
+ +
{isFetchingBudgets ? : formatPrice(available)} {isAssignable && ( -
Assigned
+
+ +
{isFetchingBudgets ? : formatPrice(pending)} )} -
Spent
+
+ +
{isFetchingBudgets ? : formatPrice(spent)} diff --git a/src/components/learner-credit-management/data/tests/utils.test.js b/src/components/learner-credit-management/data/tests/utils.test.js index 4ea9294d6e..7420be9d58 100644 --- a/src/components/learner-credit-management/data/tests/utils.test.js +++ b/src/components/learner-credit-management/data/tests/utils.test.js @@ -2,6 +2,8 @@ import { transformSubsidySummary, getBudgetStatus, orderBudgets, + getTranslatedBudgetStatus, + getTranslatedBudgetTerm, } from '../utils'; import { EXEC_ED_OFFER_TYPE } from '../constants'; @@ -206,3 +208,47 @@ describe('orderBudgets', () => { expect(sortedBudgets.map((budget) => budget.name)).toEqual(['Budget A', 'Budget B']); }); }); + +describe('getTranslatedBudgetStatus', () => { + it('should translate the budget status correctly', () => { + const intl = { formatMessage: jest.fn() }; + const status = 'Retired'; + + getTranslatedBudgetStatus(intl, status); + + expect(intl.formatMessage).toHaveBeenCalledWith({ + id: 'lcm.budgets.budget.card.status.retired', + defaultMessage: 'Retired', + description: 'Status for a retired budget', + }); + }); + it('should handle the case for an unknown value', () => { + const intl = { formatMessage: jest.fn() }; + const status = 'unknown'; + + expect(getTranslatedBudgetStatus(intl, status)).toEqual(''); + }); +}); + +describe('getTranslatedBudgetTerm', () => { + it('should translate the budget term correctly', () => { + const intl = { formatMessage: jest.fn() }; + const term = 'Expiring'; + + getTranslatedBudgetTerm(intl, term); + + expect(intl.formatMessage).toHaveBeenCalledWith({ + id: 'lcm.budgets.budget.card.term.expiring', + defaultMessage: 'Expiring', + description: 'Term for when a budget is expiring', + }); + }); + it('should handle the case when unknown or null term', () => { + const intl = { formatMessage: jest.fn() }; + const term1 = 'unknown'; + const term2 = null; + + expect(getTranslatedBudgetTerm(intl, term1)).toEqual(''); + expect(getTranslatedBudgetTerm(intl, term2)).toEqual(''); + }); +}); diff --git a/src/components/learner-credit-management/data/utils.js b/src/components/learner-credit-management/data/utils.js index 55071c12a5..2fc358df5a 100644 --- a/src/components/learner-credit-management/data/utils.js +++ b/src/components/learner-credit-management/data/utils.js @@ -455,3 +455,84 @@ export const transformSelectedRows = (selectedFlatRows) => { totalSelectedRows, }; }; + +/** + * Translates the budget status using the provided `intl` object. + * + * @param {object} intl - The `intl` object used for translation. + * @param {string} status - The status of the budget. + * @returns {string} The translated budget status. + */ +export const getTranslatedBudgetStatus = (intl, status) => { + switch (status) { + case BUDGET_STATUSES.active: + return intl.formatMessage({ + id: 'lcm.budgets.budget.card.status.active', + defaultMessage: 'Active', + description: 'Status for an active budget', + }); + case BUDGET_STATUSES.expiring: + return intl.formatMessage({ + id: 'lcm.budgets.budget.card.status.expiring', + defaultMessage: 'Expiring', + description: 'Status for an expiring budget', + }); + case BUDGET_STATUSES.expired: + return intl.formatMessage({ + id: 'lcm.budgets.budget.card.status.expired', + defaultMessage: 'Expired', + description: 'Status for an expired budget', + }); + case BUDGET_STATUSES.retired: + return intl.formatMessage({ + id: 'lcm.budgets.budget.card.status.retired', + defaultMessage: 'Retired', + description: 'Status for a retired budget', + }); + case BUDGET_STATUSES.scheduled: + return intl.formatMessage({ + id: 'lcm.budgets.budget.card.status.scheduled', + defaultMessage: 'Scheduled', + description: 'Status for a scheduled budget', + }); + default: + return ''; + } +}; + +/** + * Translates the budget term using the provided `intl` object. + * @param {object} intl - The `intl` object used for translation. + * @param {string} term - The term of the budget. + * @returns {string} The translated budget term. + */ +export const getTranslatedBudgetTerm = (intl, term) => { + switch (term) { + case 'Starts': + return intl.formatMessage({ + id: 'lcm.budgets.budget.card.term.starts', + defaultMessage: 'Starts', + description: 'Term for when a budget starts', + }); + case 'Expires': + return intl.formatMessage({ + id: 'lcm.budgets.budget.card.term.expires', + defaultMessage: 'Expires', + description: 'Term for when a budget expires', + }); + case 'Expiring': + return intl.formatMessage({ + id: 'lcm.budgets.budget.card.term.expiring', + defaultMessage: 'Expiring', + description: 'Term for when a budget is expiring', + }); + case 'Expired': + return intl.formatMessage({ + id: 'lcm.budgets.budget.card.term.expired', + defaultMessage: 'Expired', + description: 'Term for when a budget has expired', + }); + default: + return ''; + } +};