diff --git a/src/components/EnterpriseApp/data/constants.js b/src/components/EnterpriseApp/data/constants.js index 8669c4983a..6feaac51f7 100644 --- a/src/components/EnterpriseApp/data/constants.js +++ b/src/components/EnterpriseApp/data/constants.js @@ -20,7 +20,7 @@ export const BUDGET_STATUSES = { upcoming: 'Upcoming', }; -export const OFFER_TYPES = { +export const BUDGET_TYPES = { ecommerce: 'ecommerce', subsidy: 'subsidy', }; diff --git a/src/components/EnterpriseSubsidiesContext/data/hooks.js b/src/components/EnterpriseSubsidiesContext/data/hooks.js index e10f23bed0..2a5443a25e 100644 --- a/src/components/EnterpriseSubsidiesContext/data/hooks.js +++ b/src/components/EnterpriseSubsidiesContext/data/hooks.js @@ -10,7 +10,7 @@ import { camelCaseObject } from '@edx/frontend-platform/utils'; import EcommerceApiService from '../../../data/services/EcommerceApiService'; import LicenseManagerApiService from '../../../data/services/LicenseManagerAPIService'; import SubsidyApiService from '../../../data/services/EnterpriseSubsidyApiService'; -import { OFFER_TYPES } from '../../EnterpriseApp/data/constants'; +import { BUDGET_TYPES } from '../../EnterpriseApp/data/constants'; export const useEnterpriseOffers = ({ enablePortalLearnerCreditManagementScreen, enterpriseId }) => { const [offers, setOffers] = useState([]); @@ -26,9 +26,7 @@ export const useEnterpriseOffers = ({ enablePortalLearnerCreditManagementScreen, try { const [enterpriseSubsidyResponse, ecommerceApiResponse] = await Promise.all([ SubsidyApiService.getSubsidyByCustomerUUID(enterpriseId, { subsidyType: 'learner_credit' }), - EcommerceApiService.fetchEnterpriseOffers({ - isCurrent: true, - }), + EcommerceApiService.fetchEnterpriseOffers(), ]); // We have to consider both type of offers active and inactive. @@ -40,7 +38,7 @@ export const useEnterpriseOffers = ({ enablePortalLearnerCreditManagementScreen, enterpriseSubsidyResults.forEach((result) => { offerData.push({ - source: OFFER_TYPES.subsidy, + source: BUDGET_TYPES.subsidy, id: result.uuid, name: result.title, start: result.activeDatetime, @@ -51,7 +49,7 @@ export const useEnterpriseOffers = ({ enablePortalLearnerCreditManagementScreen, ecommerceOffersResults.forEach((result) => { offerData.push({ - source: OFFER_TYPES.ecommerce, + source: BUDGET_TYPES.ecommerce, id: result.id, name: result.displayName, start: result.startDatetime, diff --git a/src/components/EnterpriseSubsidiesContext/data/tests/hooks.test.js b/src/components/EnterpriseSubsidiesContext/data/tests/hooks.test.js index 3e3ad44f52..ec1c5466af 100644 --- a/src/components/EnterpriseSubsidiesContext/data/tests/hooks.test.js +++ b/src/components/EnterpriseSubsidiesContext/data/tests/hooks.test.js @@ -4,7 +4,7 @@ import { useCoupons, useCustomerAgreement, useEnterpriseOffers } from '../hooks' import EcommerceApiService from '../../../../data/services/EcommerceApiService'; import LicenseManagerApiService from '../../../../data/services/LicenseManagerAPIService'; import SubsidyApiService from '../../../../data/services/EnterpriseSubsidyApiService'; -import { OFFER_TYPES } from '../../../EnterpriseApp/data/constants'; +import { BUDGET_TYPES } from '../../../EnterpriseApp/data/constants'; jest.mock('@edx/frontend-platform/config', () => ({ getConfig: jest.fn(() => ({ @@ -52,7 +52,7 @@ describe('useEnterpriseOffers', () => { start: '2021-05-15T19:56:09Z', end: '2100-05-15T19:56:09Z', isCurrent: true, - source: OFFER_TYPES.ecommerce, + source: BUDGET_TYPES.ecommerce, }]; SubsidyApiService.getSubsidyByCustomerUUID.mockResolvedValueOnce({ @@ -71,9 +71,7 @@ describe('useEnterpriseOffers', () => { await waitForNextUpdate(); - expect(EcommerceApiService.fetchEnterpriseOffers).toHaveBeenCalledWith({ - isCurrent: true, - }); + expect(EcommerceApiService.fetchEnterpriseOffers).toHaveBeenCalled(); expect(result.current).toEqual({ offers: mockOffers, isLoading: false, @@ -133,7 +131,7 @@ describe('useEnterpriseOffers', () => { start: '2021-05-15T19:56:09Z', end: '2100-05-15T19:56:09Z', isCurrent: true, - source: OFFER_TYPES.subsidy, + source: BUDGET_TYPES.subsidy, }, { id: 'uuid', @@ -141,7 +139,7 @@ describe('useEnterpriseOffers', () => { start: '2021-05-15T19:56:09Z', end: '2100-05-15T19:56:09Z', isCurrent: true, - source: OFFER_TYPES.ecommerce, + source: BUDGET_TYPES.ecommerce, }, ]; @@ -216,7 +214,7 @@ describe('useEnterpriseOffers', () => { start: '2005-05-15T19:56:09Z', end: '2006-05-15T19:56:09Z', isCurrent: false, - source: OFFER_TYPES.subsidy, + source: BUDGET_TYPES.subsidy, }, { id: 'offer-2', @@ -224,7 +222,7 @@ describe('useEnterpriseOffers', () => { start: '2006-05-15T19:56:09Z', end: '2099-05-15T19:56:09Z', isCurrent: true, - source: OFFER_TYPES.subsidy, + source: BUDGET_TYPES.subsidy, }, ]; diff --git a/src/components/learner-credit-management/BudgetCard-V2.jsx b/src/components/learner-credit-management/BudgetCard-V2.jsx index b3ac7c695f..2e5fe3a360 100644 --- a/src/components/learner-credit-management/BudgetCard-V2.jsx +++ b/src/components/learner-credit-management/BudgetCard-V2.jsx @@ -1,39 +1,14 @@ -/* eslint-disable */ +/* eslint-disable no-nested-ternary */ import React from 'react'; import PropTypes from 'prop-types'; import { Stack, - Col, - Card, - Skeleton, } from '@edx/paragon'; import { useOfferSummary } from './data/hooks'; -import SubBudgetCard from './Budgetcard-V3'; -import { OFFER_TYPES } from '../EnterpriseApp/data/constants'; +import SubBudgetCard from './SubBudgetCard'; +import { BUDGET_TYPES } from '../EnterpriseApp/data/constants'; -const LoadingCards = () => ( - - - - - - - - - - - - - - - - - - - - -); const BudgetCard = ({ offer, enterpriseUUID, @@ -52,12 +27,11 @@ const BudgetCard = ({ } = useOfferSummary(enterpriseUUID, offer); return ( - - {isLoadingOfferSummary ? ( - - ) : offerType === OFFER_TYPES.ecommerce ? ( + + {isLoadingOfferSummary && offerType === BUDGET_TYPES.ecommerce ? ( ( { - const formattedStartDate = dayjs(start).format('MMMM D, YYYY'); - const formattedExpirationDate = dayjs(end).format('MMMM D, YYYY'); - const budgetStatus = getBudgetStatus(start, end); - - const renderActions = (id) => ( - - View budget - - ); - - const renderCardHeader = (budgetType, id) => { - const subtitle = ( - - - {formattedStartDate} - {formattedExpirationDate} - - - ); - - return ( - - {budgetStatus !== BUDGET_STATUSES.upcoming && renderActions(id)} - - )} - /> - ); - }; - - const renderCardSection = (available, spent) => ( - - - - Available - {available} - - - Spent - {spent} - - - - ); - - return ( - - - {renderCardHeader(displayName || 'Overview', id)} - {budgetStatus !== BUDGET_STATUSES.upcoming && renderCardSection(available, spent)} - - - ); -}; - -SubBudgetCard.propTypes = { - enterpriseSlug: PropTypes.string.isRequired, - id: PropTypes.string, - start: PropTypes.string, - end: PropTypes.string, - spent: PropTypes.number, - available: PropTypes.number, - displayName: PropTypes.string, -}; - -export default SubBudgetCard; diff --git a/src/components/learner-credit-management/MultipleBudgetsPage.jsx b/src/components/learner-credit-management/MultipleBudgetsPage.jsx index 3df18c465a..81f7065ac8 100644 --- a/src/components/learner-credit-management/MultipleBudgetsPage.jsx +++ b/src/components/learner-credit-management/MultipleBudgetsPage.jsx @@ -6,6 +6,7 @@ import { Col, Card, Hyperlink, + Container, } from '@edx/paragon'; import { connect } from 'react-redux'; import { Helmet } from 'react-helmet'; @@ -35,26 +36,28 @@ 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 - - - - - + + + + + + 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/SubBudgetCard.jsx b/src/components/learner-credit-management/SubBudgetCard.jsx new file mode 100644 index 0000000000..d3360cea43 --- /dev/null +++ b/src/components/learner-credit-management/SubBudgetCard.jsx @@ -0,0 +1,103 @@ +import { Link } from 'react-router-dom'; +import PropTypes from 'prop-types'; +import dayjs from 'dayjs'; +import { + Card, + Button, + Row, + Col, +} from '@edx/paragon'; + +import { BUDGET_STATUSES, ROUTE_NAMES } from '../EnterpriseApp/data/constants'; +import { formatPrice, getBudgetStatus } from './data/utils'; + +const SubBudgetCard = ({ + id, + start, + end, + available, + spent, + displayName, + enterpriseSlug, + isLoading, +}) => { + const formattedStartDate = dayjs(start).format('MMMM D, YYYY'); + const formattedExpirationDate = dayjs(end).format('MMMM D, YYYY'); + const budgetStatus = getBudgetStatus(start, end); + + const renderActions = (budgetId) => ( + + View budget + + ); + + const renderCardHeader = (budgetType, budgetId) => { + const subtitle = ( + + + {formattedStartDate} - {formattedExpirationDate} + + + ); + + return ( + + ); + }; + + const renderCardSection = (availableBalance, spentBalance) => ( + + + + Available + {formatPrice(availableBalance)} + + + Spent + {formatPrice(spentBalance)} + + + + ); + + return ( + + + {renderCardHeader(displayName || 'Overview', id)} + {budgetStatus !== BUDGET_STATUSES.upcoming && renderCardSection(available, spent)} + + + ); +}; + +SubBudgetCard.propTypes = { + enterpriseSlug: PropTypes.string.isRequired, + id: PropTypes.string, + start: PropTypes.string, + end: PropTypes.string, + spent: PropTypes.number, + isLoading: PropTypes.bool, + available: PropTypes.number, + displayName: PropTypes.string, +}; + +export default SubBudgetCard; diff --git a/src/components/learner-credit-management/data/utils.js b/src/components/learner-credit-management/data/utils.js index 15d3eae2a2..47d17e7994 100644 --- a/src/components/learner-credit-management/data/utils.js +++ b/src/components/learner-credit-management/data/utils.js @@ -127,3 +127,11 @@ export const getBudgetStatus = (startDateStr, endDateStr) => { } return BUDGET_STATUSES.expired; }; + +export const formatPrice = (price) => { + const USDollar = new Intl.NumberFormat('en-US', { + style: 'currency', + currency: 'USD', + }); + return USDollar.format(price); +}; diff --git a/src/components/learner-credit-management/tests/BudgetCard.test.jsx b/src/components/learner-credit-management/tests/BudgetCard.test.jsx index 0bffaaf5e6..d8aa511a4a 100644 --- a/src/components/learner-credit-management/tests/BudgetCard.test.jsx +++ b/src/components/learner-credit-management/tests/BudgetCard.test.jsx @@ -14,7 +14,7 @@ import '@testing-library/jest-dom/extend-expect'; import { IntlProvider } from '@edx/frontend-platform/i18n'; import BudgetCard from '../BudgetCard-V2'; import { useOfferSummary, useOfferRedemptions } from '../data/hooks'; -import { OFFER_TYPES } from '../../EnterpriseApp/data/constants'; +import { BUDGET_TYPES } from '../../EnterpriseApp/data/constants'; jest.mock('../data/hooks'); useOfferSummary.mockReturnValue({ @@ -122,7 +122,7 @@ describe('', () => { name: mockOfferDisplayName, start: '2022-01-01', end: '2023-01-01', - offerType: OFFER_TYPES.ecommerce, + offerType: BUDGET_TYPES.ecommerce, }; const mockOfferRedemption = { created: '2022-02-01',
- We were unable to find any budgets for your organization. Please contact - Customer Support if you have questions. -
+ We were unable to find any budgets for your organization. Please contact + Customer Support if you have questions. +