diff --git a/src/components/BudgetExpiryAlertAndModal/data/expiryThresholds.js b/src/components/BudgetExpiryAlertAndModal/data/expiryThresholds.js index ab8c384dac..b91463fa38 100644 --- a/src/components/BudgetExpiryAlertAndModal/data/expiryThresholds.js +++ b/src/components/BudgetExpiryAlertAndModal/data/expiryThresholds.js @@ -3,76 +3,168 @@ import parse from 'html-react-parser'; import { PLAN_EXPIRY_VARIANTS } from './constants'; const expiryThresholds = { - 120: ({ date }) => ({ + 120: ({ intl, date }) => ({ notificationTemplate: { - title: 'Your Learner Credit plan expires soon', + title: intl.formatMessage({ + id: 'adminPortal.leaernerCredit.expiryNotification.title', + defaultMessage: 'Your Learner Credit plan expires soon', + description: 'Title for the notification that the Learner Credit plan is expiring soon.', + }), variant: 'info', - message: `Your Learner Credit plan expires ${date}. Contact support today to renew your plan and keep people learning.`, + message: intl.formatMessage({ + id: 'adminPortal.leaernerCredit.expiryNotification.message', + defaultMessage: 'Your Learner Credit plan expires {date}. Contact support today to renew your plan and keep people learning.', + description: 'Message for the notification that the Learner Credit plan is expiring soon.', + }, { date }), dismissible: true, }, modalTemplate: { - title: 'Your plan expires soon', - message: parse(sanitizeHTML(`Your Learner Credit plan expires ${date}. Contact support today to renew your plan and keep people learning.`)), + title: intl.formatMessage({ + id: 'adminPortal.leaernerCredit.expiryModal.title', + defaultMessage: 'Your plan expires soon', + description: 'Title for the modal that the Learner Credit plan is expiring soon.', + }), + message: parse(sanitizeHTML(intl.formatMessage({ + id: 'adminPortal.leaernerCredit.expiryModal.message', + defaultMessage: 'Your Learner Credit plan expires {date}. Contact support today to renew your plan and keep people learning.', + description: 'Message for the modal that the Learner Credit plan is expiring soon.', + }, { date }))), }, variant: PLAN_EXPIRY_VARIANTS.expiring, }), - 90: ({ date }) => ({ + 90: ({ intl, date }) => ({ notificationTemplate: { - title: 'Reminder: Your Learner Credit plan expires soon', + title: intl.formatMessage({ + id: 'adminPortal.learnerCredit.expiryReminderNotification.title', + defaultMessage: 'Reminder: Your Learner Credit plan expires soon', + description: 'Title for the notification that the Learner Credit plan is expiring soon.', + }), variant: 'info', - message: `Your Learner Credit plan expires ${date}. Contact support today to renew your plan and keep people learning.`, + message: intl.formatMessage({ + id: 'adminPortal.learnerCredit.expiryReminderNotification.message', + defaultMessage: 'Your Learner Credit plan expires {date}. Contact support today to renew your plan and keep people learning.', + description: 'Message for the notification that the Learner Credit plan is expiring soon.', + }, { date }), dismissible: true, }, modalTemplate: { - title: 'Reminder: Your plan expires soon', - message: parse(sanitizeHTML(`Your Learner Credit plan expires ${date}. Contact support today to renew your plan and keep people learning.`)), + title: intl.formatMessage({ + id: 'adminPortal.learnerCredit.expiryReminderModal.title', + defaultMessage: 'Reminder: Your plan expires soon', + description: 'Title for the modal that the Learner Credit plan is expiring soon.', + }), + message: parse(sanitizeHTML(intl.formatMessage({ + id: 'adminPortal.learnerCredit.expiryReminderModal.message', + defaultMessage: 'Your Learner Credit plan expires {date}. Contact support today to renew your plan and keep people learning.', + description: 'Message for the modal that the Learner Credit plan is expiring soon.', + }, { date }))), }, variant: PLAN_EXPIRY_VARIANTS.expiring, }), - 60: ({ date }) => ({ + 60: ({ intl, date }) => ({ notificationTemplate: { - title: `Your Learner Credit plan expires ${date}`, + title: intl.formatMessage({ + id: 'adminPortal.learnerCredit.expiresNotification.title', + defaultMessage: 'Your Learner Credit plan expires {date}', + description: 'Title for the notification that the Learner Credit plan is expiring.', + }, { date }), variant: 'warning', - message: 'When your Learner Credit plan expires, you will no longer have access to administrative functions and the remaining balance of your budget(s) will be unusable. Contact support today to renew your plan.', + message: intl.formatMessage({ + id: 'adminPortal.learnerCredit.expiresNotification.message', + defaultMessage: 'When your Learner Credit plan expires, you will no longer have access to administrative functions and the remaining balance of your budget(s) will be unusable. Contact support today to renew your plan.', + description: 'Message for the notification that the Learner Credit plan is expiring.', + }), dismissible: true, }, modalTemplate: { - title: `Your Learner Credit plan expires ${date}`, - message: parse(sanitizeHTML(`Your Learner Credit plan expires ${date}. Contact support today to renew your plan and keep people learning.`)), + title: intl.formatMessage({ + id: 'adminPortal.learnerCredit.expiresModal.title', + defaultMessage: 'Your Learner Credit plan expires {date}', + description: 'Title for the modal that the Learner Credit plan is expiring.', + }, { date }), + message: parse(sanitizeHTML(intl.formatMessage({ + id: 'adminPortal.learnerCredit.expiresModal.message', + defaultMessage: 'Your Learner Credit plan expires {date}. Contact support today to renew your plan and keep people learning.', + description: 'Message for the modal that the Learner Credit plan is expiring.', + }, { date }))), }, variant: PLAN_EXPIRY_VARIANTS.expiring, }), - 30: ({ date }) => ({ + 30: ({ intl, date }) => ({ notificationTemplate: { - title: 'Your Learner Credit plan expires in less than 30 days', + title: intl.formatMessage({ + id: 'adminPostal.learnerCredit.expiresInThirtyDaysNotification.title', + defaultMessage: 'Your Learner Credit plan expires in less than 30 days', + description: 'Title for the notification that the Learner Credit plan is expiring in less than 30 days.', + }), variant: 'danger', - message: 'When your plan expires you will lose access to administrative functions and the remaining balance of your plan’s budget(s) will be unusable. Contact support today to renew your plan.', + message: intl.formatMessage({ + id: 'adminPostal.learnerCredit.expiresInThirtyDaysNotification.message', + defaultMessage: 'When your plan expires you will lose access to administrative functions and the remaining balance of your plan{apostrophe}s budget(s) will be unusable. Contact support today to renew your plan.', + description: 'Message for the notification that the Learner Credit plan is expiring in less than 30 days.', + }, { aposrophe: "'" }), }, modalTemplate: { - title: 'Your Learner Credit plan expires in less than 30 days', - message: parse(sanitizeHTML(`

Your Learner Credit plan expires ${date}. Contact support today to renew your plan and keep people learning.

`)), + title: intl.formatMessage({ + id: 'adminPostal.learnerCredit.expiresInThirtyDaysModal.title', + defaultMessage: 'Your Learner Credit plan expires in less than 30 days', + description: 'Title for the modal that the Learner Credit plan is expiring in less than 30 days.', + }), + message: parse(sanitizeHTML( + intl.formatMessage({ + id: 'adminPostal.learnerCredit.expiresInThirtyDaysModal.message', + defaultMessage: 'Your Learner Credit plan expires {date}. Contact support today to renew your plan and keep people learning.', + description: 'Message for the modal that the Learner Credit plan is expiring in less than 30 days.', + }, { date }), + )), }, variant: PLAN_EXPIRY_VARIANTS.expiring, }), - 10: ({ date, days, hours }) => ({ + 10: ({ + intl, date, days, hours, + }) => ({ notificationTemplate: { - title: `Reminder: Your Learner Credit plan expires ${date}`, + title: intl.formatMessage({ + id: 'adminPortal.learnerCreditPlan.expiresInTenDaysNotification.title', + defaultMessage: 'Reminder: Your Learner Credit plan expires {date}', + description: 'Title for the notification that the Learner Credit plan is expiring.', + }, { date }), variant: 'danger', - message: parse(sanitizeHTML(`Your Learner Credit plan expires in ${days} days and ${hours} hours. Contact support today to renew your plan.`)), + message: parse(sanitizeHTML(intl.formatMessage({ + id: 'adminPortal.learnerCreditPlan.expiresInTenDaysNotification.message', + defaultMessage: 'Your Learner Credit plan expires in {days} days and {hours} hours. Contact support today to renew your plan.', + description: 'Message for the notification that the Learner Credit plan is expiring.', + }, { days, hours, strong: (str) => `${str}` }))), }, modalTemplate: { - title: `Reminder: Your Learner Credit plan expires ${date}`, - message: parse(sanitizeHTML(`

Your Learner Credit plan expires ${date}. Contact support today to renew your plan and keep people learning.

`)), + title: intl.formatMessage({ + id: 'adminPortal.learnerCreditPlan.expiresInTenDaysModal.title', + defaultMessage: 'Reminder: Your Learner Credit plan expires {date}', + description: 'Title for the modal that the Learner Credit plan is expiring.', + }, { date }), + message: parse(sanitizeHTML(intl.formatMessage({ + id: 'adminPortal.learnerCreditPlan.expiresInTenDaysModal.message', + defaultMessage: 'Your Learner Credit plan expires {date}. Contact support today to renew your plan and keep people learning.', + description: 'Message for the modal that the Learner Credit plan is expiring.', + }, { date }))), }, variant: PLAN_EXPIRY_VARIANTS.expiring, }), - 0: ({ date }) => ({ + 0: ({ intl, date }) => ({ notificationTemplate: null, modalTemplate: { - title: 'Your Learner Credit plan has expired', + title: intl.formatMessage({ + id: 'adminPortal.learnerCreditPlan.expiredModal.title', + defaultMessage: 'Your Learner Credit plan has expired', + description: 'Title for the modal that the Learner Credit plan has expired.', + }), message: parse(sanitizeHTML( - `

Your Learner Credit Plan expired on ${date}. You are no longer have access to administrative functions and the remaining balance of your plan's budget(s) are no longer available to spend

` - + '

Please contact your representative if you have any questions or concerns.

', + intl.formatMessage({ + id: 'adminPortal.learnerCreditPlan.expiredModal.message', + defaultMessage: `Your Learner Credit plan expired on {date}. You no longer have access to administrative functions and the remaining balance of your plan{apostrophe}s budget(s) are no longer available to spend. + Please contact your representative if you have any questions or concerns.`, + description: 'Message for the modal that the Learner Credit plan has expired.', + }, { date, apostrophe: "'" }), )), }, variant: PLAN_EXPIRY_VARIANTS.expired, diff --git a/src/components/BudgetExpiryAlertAndModal/data/hooks/useExpiry.jsx b/src/components/BudgetExpiryAlertAndModal/data/hooks/useExpiry.jsx index a150d97649..e2eefeaa9c 100644 --- a/src/components/BudgetExpiryAlertAndModal/data/hooks/useExpiry.jsx +++ b/src/components/BudgetExpiryAlertAndModal/data/hooks/useExpiry.jsx @@ -1,4 +1,5 @@ import { useState, useEffect } from 'react'; +import { useIntl } from '@edx/frontend-platform/i18n'; import { getEnterpriseBudgetExpiringAlertCookieName, getEnterpriseBudgetExpiringModalCookieName, @@ -7,6 +8,7 @@ import { } from '../utils'; const useExpiry = (enterpriseId, budgets, modalOpen, modalClose, alertOpen, alertClose) => { + const intl = useIntl(); const [notification, setNotification] = useState(null); const [expirationThreshold, setExpirationThreshold] = useState(null); const [modal, setModal] = useState(null); @@ -41,7 +43,7 @@ const useExpiry = (enterpriseId, budgets, modalOpen, modalClose, alertOpen, aler budgetsToConsiderForExpirationMessaging[0], ); - const { thresholdKey, threshold } = getExpirationMetadata(earliestExpiryBudget.end); + const { thresholdKey, threshold } = getExpirationMetadata(intl, earliestExpiryBudget.end); if (thresholdKey !== null) { const { notificationTemplate, modalTemplate } = threshold; @@ -74,7 +76,7 @@ const useExpiry = (enterpriseId, budgets, modalOpen, modalClose, alertOpen, aler if (!isAlertDismissed) { alertOpen(); } - }, [budgets, enterpriseId, modalOpen, alertOpen]); + }, [budgets, enterpriseId, modalOpen, alertOpen, intl]); const dismissModal = () => { const seenCurrentExpirationModalCookieName = getEnterpriseBudgetExpiringModalCookieName({ diff --git a/src/components/BudgetExpiryAlertAndModal/data/hooks/useExpiry.test.jsx b/src/components/BudgetExpiryAlertAndModal/data/hooks/useExpiry.test.jsx index 0dd2481486..dde8b300da 100644 --- a/src/components/BudgetExpiryAlertAndModal/data/hooks/useExpiry.test.jsx +++ b/src/components/BudgetExpiryAlertAndModal/data/hooks/useExpiry.test.jsx @@ -1,6 +1,7 @@ import { renderHook } from '@testing-library/react-hooks'; import dayjs from 'dayjs'; import duration from 'dayjs/plugin/duration'; // Assuming this is the path to your expiryThresholds file +import { createIntl, IntlProvider } from '@edx/frontend-platform/i18n'; import useExpiry from './useExpiry'; import expiryThresholds from '../expiryThresholds'; import { formatDate } from '../../../learner-credit-management/data'; @@ -20,16 +21,25 @@ const offsetDays = { 10: dayjs().add(10, 'day'), 1: dayjs().subtract(1, 'day'), }; +const intl = createIntl({ + locale: 'en', + messages: {}, +}); describe('useExpiry', () => { beforeEach(() => { jest.clearAllMocks(); }); - + const wrapper = ({ children }) => ( + + {children} + + ); it.each([ { endDate: offsetDays['120'], expected: expiryThresholds[120]({ + intl, date: formatDate(offsetDays['120'].toString()), }), isNonExpiredBudget: true, @@ -37,6 +47,7 @@ describe('useExpiry', () => { { endDate: offsetDays['90'], expected: expiryThresholds[90]({ + intl, date: formatDate(offsetDays['90'].toString()), }), isNonExpiredBudget: true, @@ -44,6 +55,7 @@ describe('useExpiry', () => { { endDate: offsetDays['60'], expected: expiryThresholds[60]({ + intl, date: formatDate(offsetDays['60'].toString()), }), isNonExpiredBudget: true, @@ -51,6 +63,7 @@ describe('useExpiry', () => { { endDate: offsetDays['30'], expected: expiryThresholds[30]({ + intl, date: formatDate(offsetDays['30'].toString()), }), isNonExpiredBudget: true, @@ -58,6 +71,7 @@ describe('useExpiry', () => { { endDate: offsetDays['10'], expected: expiryThresholds[10]({ + intl, date: formatDate(offsetDays['10'].toString()), days: dayjs.duration(offsetDays['10'].diff(dayjs())).days(), hours: dayjs.duration(offsetDays['10'].diff(dayjs())).hours(), @@ -67,14 +81,14 @@ describe('useExpiry', () => { { endDate: offsetDays['1'], expected: expiryThresholds[0]({ + intl, date: formatDate(offsetDays['1'].toString()), }), isNonExpiredBudget: false, }, ])('displays correct notification and modal when plan is expiring in %s days', ({ endDate, expected, isNonExpiredBudget }) => { const budgets = [{ end: endDate }]; // Mock data with an expiring budget - - const { result } = renderHook(() => useExpiry('enterpriseId', budgets, modalOpen, modalClose, alertOpen, alertClose)); + const { result } = renderHook(() => useExpiry('enterpriseId', budgets, modalOpen, modalClose, alertOpen, alertClose), { wrapper }); expect(result.current.notification).toEqual(expected.notificationTemplate); expect(result.current.modal).toEqual(expected.modalTemplate); @@ -86,8 +100,7 @@ describe('useExpiry', () => { const expiredBudget = { end: dayjs().subtract(1, 'day') }; const nonExpiredBudget = { end: dayjs().add(200, 'day') }; const budgets = [expiredBudget, nonExpiredBudget]; - - const { result } = renderHook(() => useExpiry('enterpriseId', budgets, modalOpen, modalClose, alertOpen, alertClose)); + const { result } = renderHook(() => useExpiry('enterpriseId', budgets, modalOpen, modalClose, alertOpen, alertClose), { wrapper }); expect(result.current.notification).toEqual(null); expect(result.current.modal).toEqual(null); diff --git a/src/components/BudgetExpiryAlertAndModal/data/utils.js b/src/components/BudgetExpiryAlertAndModal/data/utils.js index 60805a7f2a..f289c13ce3 100644 --- a/src/components/BudgetExpiryAlertAndModal/data/utils.js +++ b/src/components/BudgetExpiryAlertAndModal/data/utils.js @@ -22,7 +22,7 @@ export const getExpiredAndNonExpiredBudgets = (budgets) => { }; }; -export const getExpirationMetadata = (endDateStr) => { +export const getExpirationMetadata = (intl, endDateStr) => { const endDate = dayjs(endDateStr); const today = dayjs(); const durationDiff = dayjs.duration(endDate.diff(today)); @@ -40,6 +40,7 @@ export const getExpirationMetadata = (endDateStr) => { return { thresholdKey, threshold: ExpiryThresholds[thresholdKey]({ + intl, date: endDate.format('MMM D, YYYY'), days: durationDiff.days(), hours: durationDiff.hours(), @@ -48,8 +49,8 @@ export const getExpirationMetadata = (endDateStr) => { }; }; -export const isPlanApproachingExpiry = (endDateStr) => { - const { thresholdKey, threshold } = getExpirationMetadata(endDateStr); +export const isPlanApproachingExpiry = (intl, endDateStr) => { + const { thresholdKey, threshold } = getExpirationMetadata(intl, endDateStr); if (!thresholdKey) { return false; diff --git a/src/components/learner-credit-management/BudgetOverviewContent.jsx b/src/components/learner-credit-management/BudgetOverviewContent.jsx index 219d388f47..b1edf7556a 100644 --- a/src/components/learner-credit-management/BudgetOverviewContent.jsx +++ b/src/components/learner-credit-management/BudgetOverviewContent.jsx @@ -3,7 +3,7 @@ import { connect } from 'react-redux'; import PropTypes from 'prop-types'; import { Card, Skeleton } from '@openedx/paragon'; -import { FormattedMessage } from '@edx/frontend-platform/i18n'; +import { FormattedMessage, useIntl } from '@edx/frontend-platform/i18n'; import { useBudgetDetailHeaderData, useBudgetId, @@ -19,6 +19,7 @@ const BudgetOverviewContent = ({ enterpriseUUID, enterpriseFeatures, }) => { + const intl = useIntl(); const { subsidyAccessPolicyId, enterpriseOfferId } = useBudgetId(); const budgetType = (enterpriseOfferId !== null) ? BUDGET_TYPES.ecommerce : BUDGET_TYPES.policy; @@ -43,6 +44,7 @@ const BudgetOverviewContent = ({ date, isAssignable, } = useBudgetDetailHeaderData({ + intl, subsidyAccessPolicy, subsidySummary, budgetId: policyOrOfferId, diff --git a/src/components/learner-credit-management/MultipleBudgetsPicker.jsx b/src/components/learner-credit-management/MultipleBudgetsPicker.jsx index e65a192f0b..2c702f9f99 100644 --- a/src/components/learner-credit-management/MultipleBudgetsPicker.jsx +++ b/src/components/learner-credit-management/MultipleBudgetsPicker.jsx @@ -20,11 +20,12 @@ const MultipleBudgetsPicker = ({ enterpriseSlug, enableLearnerPortal, }) => { - const orderedBudgets = orderBudgets(budgets); const intl = useIntl(); + const orderedBudgets = orderBudgets(intl, budgets); const rows = useMemo( () => orderedBudgets.map(budget => { const budgetLabel = getBudgetStatus({ + intl, startDateStr: budget.start, endDateStr: budget.end, isBudgetRetired: budget.isRetired, @@ -38,11 +39,12 @@ const MultipleBudgetsPicker = ({ enableLearnerPortal, }); }), - [orderedBudgets, enterpriseUUID, enterpriseSlug, enableLearnerPortal], + [orderedBudgets, enterpriseUUID, enterpriseSlug, enableLearnerPortal, intl], ); const budgetLabels = orderedBudgets.map(budget => ( getBudgetStatus({ + intl, startDateStr: budget.start, endDateStr: budget.end, isBudgetRetired: budget.isRetired, diff --git a/src/components/learner-credit-management/SubBudgetCard.jsx b/src/components/learner-credit-management/SubBudgetCard.jsx index b3c558afef..67f39cbb44 100644 --- a/src/components/learner-credit-management/SubBudgetCard.jsx +++ b/src/components/learner-credit-management/SubBudgetCard.jsx @@ -77,6 +77,7 @@ const BaseSubBudgetCard = ({ }); const intl = useIntl(); const budgetLabel = getBudgetStatus({ + intl, startDateStr: start, endDateStr: end, isBudgetRetired: isRetired, diff --git a/src/components/learner-credit-management/data/hooks/useBudgetDetailHeaderData.js b/src/components/learner-credit-management/data/hooks/useBudgetDetailHeaderData.js index 71d4da89d3..7165913223 100644 --- a/src/components/learner-credit-management/data/hooks/useBudgetDetailHeaderData.js +++ b/src/components/learner-credit-management/data/hooks/useBudgetDetailHeaderData.js @@ -23,10 +23,11 @@ const transformSubsidySummaryToPolicy = (subsidySummary, enterpriseOfferMetadata return transformedData; }; -const assignBudgetStatus = (policy) => { +const assignBudgetStatus = (intl, policy) => { const { status, badgeVariant, term, date, } = getBudgetStatus({ + intl, startDateStr: policy.subsidyActiveDatetime, endDateStr: policy.subsidyExpirationDatetime, isBudgetRetired: policy.retired, @@ -63,6 +64,7 @@ const assignBudgetDetails = (policy, isTopDownAssignmentEnabled) => { }; const useBudgetDetailHeaderData = ({ + intl, subsidyAccessPolicy, subsidySummary, budgetId, @@ -84,7 +86,7 @@ const useBudgetDetailHeaderData = ({ }; if (policy) { - Object.assign(transformedPolicyData, assignBudgetStatus(policy)); + Object.assign(transformedPolicyData, assignBudgetStatus(intl, policy)); Object.assign(transformedPolicyData, assignBudgetDetails(policy, isTopDownAssignmentEnabled)); } return transformedPolicyData; 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 7420be9d58..a4c9bf24e8 100644 --- a/src/components/learner-credit-management/data/tests/utils.test.js +++ b/src/components/learner-credit-management/data/tests/utils.test.js @@ -1,3 +1,4 @@ +import { createIntl } from '@edx/frontend-platform/i18n'; import { transformSubsidySummary, getBudgetStatus, @@ -7,6 +8,10 @@ import { } from '../utils'; import { EXEC_ED_OFFER_TYPE } from '../constants'; +const intl = createIntl({ + locale: 'en', + messages: {}, +}); describe('transformSubsidySummary', () => { it('should return null if there is no budgetSummary', () => { expect(transformSubsidySummary()).toBeNull(); @@ -128,6 +133,7 @@ describe('getBudgetStatus', () => { const endDateStr = '2023-08-31'; const currentDateStr = '2023-09-28'; const result = getBudgetStatus({ + intl, startDateStr, endDateStr, currentDate: new Date(currentDateStr), @@ -181,7 +187,7 @@ const budgets = [ describe('orderBudgets', () => { it('should sort offers correctly', () => { - const sortedBudgets = orderBudgets(budgets); + const sortedBudgets = orderBudgets(intl, budgets); // Expected order: // Active budgets (Budget 2) @@ -192,7 +198,7 @@ describe('orderBudgets', () => { }); it('should handle empty input', () => { - const sortedBudgets = orderBudgets([]); + const sortedBudgets = orderBudgets(intl, []); expect(sortedBudgets).toEqual([]); }); @@ -202,7 +208,7 @@ describe('orderBudgets', () => { { name: 'Budget B', start: '2023-01-01T00:00:00Z', end: '2023-01-15T00:00:00Z' }, ]; - const sortedBudgets = orderBudgets(duplicateBudgets); + const sortedBudgets = orderBudgets(intl, duplicateBudgets); // Since both offers have the same status ("active") and end date, they should be sorted alphabetically by name. expect(sortedBudgets.map((budget) => budget.name)).toEqual(['Budget A', 'Budget B']); @@ -211,44 +217,44 @@ describe('orderBudgets', () => { describe('getTranslatedBudgetStatus', () => { it('should translate the budget status correctly', () => { - const intl = { formatMessage: jest.fn() }; + const mockintl = { formatMessage: jest.fn() }; const status = 'Retired'; - getTranslatedBudgetStatus(intl, status); + getTranslatedBudgetStatus(mockintl, status); - expect(intl.formatMessage).toHaveBeenCalledWith({ + expect(mockintl.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 mockintl = { formatMessage: jest.fn() }; const status = 'unknown'; - expect(getTranslatedBudgetStatus(intl, status)).toEqual(''); + expect(getTranslatedBudgetStatus(mockintl, status)).toEqual(''); }); }); describe('getTranslatedBudgetTerm', () => { it('should translate the budget term correctly', () => { - const intl = { formatMessage: jest.fn() }; + const mockintl = { formatMessage: jest.fn() }; const term = 'Expiring'; - getTranslatedBudgetTerm(intl, term); + getTranslatedBudgetTerm(mockintl, term); - expect(intl.formatMessage).toHaveBeenCalledWith({ + expect(mockintl.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 mockintl = { formatMessage: jest.fn() }; const term1 = 'unknown'; const term2 = null; - expect(getTranslatedBudgetTerm(intl, term1)).toEqual(''); - expect(getTranslatedBudgetTerm(intl, term2)).toEqual(''); + expect(getTranslatedBudgetTerm(mockintl, term1)).toEqual(''); + expect(getTranslatedBudgetTerm(mockintl, term2)).toEqual(''); }); }); diff --git a/src/components/learner-credit-management/data/utils.js b/src/components/learner-credit-management/data/utils.js index 65e86ec30e..0c6b0c2116 100644 --- a/src/components/learner-credit-management/data/utils.js +++ b/src/components/learner-credit-management/data/utils.js @@ -159,6 +159,7 @@ export const isUUID = (id) => /^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0- // Utility function to check the budget status export const getBudgetStatus = ({ + intl, startDateStr, endDateStr, isBudgetRetired, @@ -188,7 +189,7 @@ export const getBudgetStatus = ({ }; } - if (isPlanApproachingExpiry(endDateStr)) { + if (isPlanApproachingExpiry(intl, endDateStr)) { return { status: BUDGET_STATUSES.expiring, badgeVariant: 'warning', @@ -234,7 +235,7 @@ export const formatPrice = (price, options = {}) => { * @param {Array} budgets - An array of budget objects. * @returns {Array} - The sorted array of budget objects. */ -export const orderBudgets = (budgets) => { +export const orderBudgets = (intl, budgets) => { const statusOrder = { Expiring: 1, Active: 1, @@ -245,11 +246,13 @@ export const orderBudgets = (budgets) => { budgets?.sort((budgetA, budgetB) => { const statusA = getBudgetStatus({ + intl, startDateStr: budgetA.start, endDateStr: budgetA.end, isBudgetRetired: budgetA.isRetired, }).status; const statusB = getBudgetStatus({ + intl, startDateStr: budgetB.start, endDateStr: budgetB.end, isBudgetRetired: budgetB.isRetired, diff --git a/src/components/learner-credit-management/invite-modal/InviteModalBudgetCard.jsx b/src/components/learner-credit-management/invite-modal/InviteModalBudgetCard.jsx index f0b4ba5ed8..e1e444f9e1 100644 --- a/src/components/learner-credit-management/invite-modal/InviteModalBudgetCard.jsx +++ b/src/components/learner-credit-management/invite-modal/InviteModalBudgetCard.jsx @@ -4,6 +4,7 @@ import PropTypes from 'prop-types'; import { Card, Col, Row, Skeleton, } from '@openedx/paragon'; +import { useIntl } from '@edx/frontend-platform/i18n'; import { makePlural } from '../../../utils'; import { @@ -21,6 +22,7 @@ const InviteModalBudgetCard = ({ enterpriseUUID, enterpriseFeatures, }) => { + const intl = useIntl(); const { subsidyAccessPolicyId, enterpriseOfferId } = useBudgetId(); const { data: subsidyAccessPolicy } = useSubsidyAccessPolicy(subsidyAccessPolicyId); const { data } = useEnterpriseGroupLearners(subsidyAccessPolicy.groupAssociations[0]); @@ -46,6 +48,7 @@ const InviteModalBudgetCard = ({ date, isAssignable, } = useBudgetDetailHeaderData({ + intl, subsidyAccessPolicy, subsidySummary, budgetId: policyOrOfferId, diff --git a/src/components/subscriptions/expiration/SubscriptionExpiredModal.jsx b/src/components/subscriptions/expiration/SubscriptionExpiredModal.jsx index 370c151ad5..8e30fb8c6c 100644 --- a/src/components/subscriptions/expiration/SubscriptionExpiredModal.jsx +++ b/src/components/subscriptions/expiration/SubscriptionExpiredModal.jsx @@ -2,6 +2,7 @@ import React, { useContext } from 'react'; import PropTypes from 'prop-types'; import { ModalDialog, ActionRow } from '@openedx/paragon'; +import { FormattedMessage } from '@edx/frontend-platform/i18n'; import { configuration } from '../../../config'; import Img from '../../Img'; import { formatTimestamp } from '../../../utils'; @@ -27,15 +28,27 @@ const SubscriptionExpiredModal = ({ edX logo

- Your subscription contract expired on {formatTimestamp({ timestamp: expirationDate })}. - The edX customer support team is here to help! Get in touch today to renew your subscription - and access your subscription management details. + {chunks}, + }} + />

- Dismiss +