Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP] feat: show all enterprise budgets regardless of plan and route correctly #1031

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ dist/

# emacs
*~
.projectile

# edx
.env.private
Expand Down
4 changes: 2 additions & 2 deletions src/components/ContentHighlights/data/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -43,10 +43,10 @@ export const TAB_TITLES = {
export const MAX_HIGHLIGHT_TITLE_LENGTH = 60;

// Max highlight sets per enteprise curation
export const MAX_HIGHLIGHT_SETS_PER_ENTERPRISE_CURATION = 8;
export const MAX_HIGHLIGHT_SETS_PER_ENTERPRISE_CURATION = 12;

// Max number of content items per highlight set
export const MAX_CONTENT_ITEMS_PER_HIGHLIGHT_SET = 12;
export const MAX_CONTENT_ITEMS_PER_HIGHLIGHT_SET = 24;

// Max number of content items displayed from search results
export const MAX_PAGE_SIZE = 24;
Expand Down
7 changes: 7 additions & 0 deletions src/components/EnterpriseApp/EnterpriseAppRoutes.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ import { PlotlyAnalyticsPage } from '../PlotlyAnalytics';
import { ROUTE_NAMES } from './data/constants';
import BulkEnrollmentResultsDownloadPage from '../BulkEnrollmentResultsDownloadPage';
import LearnerCreditManagement from '../learner-credit-management';
import BudgetDetailPage from '../learner-credit-management/BudgetDetailPage';
import { EnterpriseSubsidiesContext } from '../EnterpriseSubsidiesContext';
import ContentHighlights from '../ContentHighlights';

Expand Down Expand Up @@ -105,6 +106,12 @@ const EnterpriseAppRoutes = ({
/>
)}

<Route
exact
path={`${baseUrl}/admin/${ROUTE_NAMES.learnerCredit}/:id`}
component={BudgetDetailPage}
/>

{enableContentHighlightsPage && (
<Route
path={`${baseUrl}/admin/${ROUTE_NAMES.contentHighlights}`}
Expand Down
6 changes: 6 additions & 0 deletions src/components/EnterpriseApp/data/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,9 @@ export const ROUTE_NAMES = {
subscriptionManagement: 'subscriptions',
contentHighlights: 'content-highlights',
};

export const BUDGET_STATUSES = {
active: 'Active',
expired: 'Expired',
upcoming: 'Upcoming',
};
71 changes: 42 additions & 29 deletions src/components/EnterpriseSubsidiesContext/data/hooks.js
Original file line number Diff line number Diff line change
Expand Up @@ -30,38 +30,51 @@ export const useEnterpriseOffers = ({ enablePortalLearnerCreditManagementScreen,
}),
]);

// If there are no subsidies in enterprise, fall back to the e-commerce API.
let { results } = camelCaseObject(enterpriseSubsidyResponse.data);
let source = 'subsidyApi';

if (results.length === 0) {
results = camelCaseObject(ecommerceApiResponse.data.results);
source = 'ecommerceApi';
// We have to conside both type of offers active and inactive.

const enterpriseResults = camelCaseObject(enterpriseSubsidyResponse.data).results;
const ecommerceResults = camelCaseObject(ecommerceApiResponse.data.results);

const offerData = [];

for (let i = 0; i < enterpriseResults.length; i++) {
const subsidy = enterpriseResults[i];
const source = 'subsidyApi';
const { isActive } = subsidy; // Always check isActive for enterprise subsidies
const isCurrent = isActive; // You can adjust this based on your specific requirements
const activeSubsidyData = {
id: subsidy.uuid,
name: subsidy.title,
start: subsidy.activeDatetime,
end: subsidy.expirationDatetime,
isCurrent,
source,
};
offerData.push(activeSubsidyData);
if (isActive) {
setCanManageLearnerCredit(true);
}
}
let activeSubsidyFound = false;
if (results.length !== 0) {
let subsidy = results[0];
const offerData = [];
let activeSubsidyData = {};
for (let i = 0; i < results.length; i++) {
subsidy = results[i];
activeSubsidyFound = source === 'ecommerceApi'
? subsidy.isCurrent
: subsidy.isActive;
if (activeSubsidyFound === true) {
activeSubsidyData = {
id: subsidy.uuid || subsidy.id,
name: subsidy.title || subsidy.displayName,
start: subsidy.activeDatetime || subsidy.startDatetime,
end: subsidy.expirationDatetime || subsidy.endDatetime,
isCurrent: activeSubsidyFound,
};
offerData.push(activeSubsidyData);
setCanManageLearnerCredit(true);
}

for (let i = 0; i < ecommerceResults.length; i++) {
const subsidy = ecommerceResults[i];
const source = 'ecommerceApi';
const { isCurrent } = subsidy;
const activeSubsidyData = {
id: subsidy.id,
name: subsidy.displayName,
start: subsidy.startDatetime,
end: subsidy.endDatetime,
isCurrent,
source,
};
offerData.push(activeSubsidyData);
if (isCurrent) {
setCanManageLearnerCredit(true);
}
setOffers(offerData);
}

setOffers(offerData);
} catch (error) {
logError(error);
} finally {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,115 @@
/* eslint-disable react/prop-types */
import React from 'react';
import { Provider } from 'react-redux';
import thunk from 'redux-thunk';
import configureMockStore from 'redux-mock-store';
import {
screen,
render,
} from '@testing-library/react';
import '@testing-library/jest-dom/extend-expect';

import { IntlProvider } from '@edx/frontend-platform/i18n';
import { MemoryRouter } from 'react-router-dom';
import BudgetDetailPage from '../../../learner-credit-management/BudgetDetailPage';
import { useOfferSummary, useOfferRedemptions } from '../../../learner-credit-management/data/hooks';
import { EXEC_ED_OFFER_TYPE } from '../../../learner-credit-management/data/constants';
import { EnterpriseSubsidiesContext } from '../..';

jest.mock('../../../learner-credit-management/data/hooks');

useOfferSummary.mockReturnValue({
isLoading: false,
offerSummary: null,
});
useOfferRedemptions.mockReturnValue({
isLoading: false,
offerRedemptions: {
itemCount: 0,
pageCount: 0,
results: [],
},
fetchOfferRedemptions: jest.fn(),
});

const mockStore = configureMockStore([thunk]);
const getMockStore = store => mockStore(store);
const enterpriseId = 'test-enterprise';
const enterpriseUUID = '1234';
const initialStore = {
portalConfiguration: {
enterpriseId,
enterpriseSlug: enterpriseId,

},
};
const store = getMockStore({ ...initialStore });

const mockEnterpriseOfferId = '123';

const mockOfferDisplayName = 'Test Enterprise Offer';
const mockOfferSummary = {
totalFunds: 5000,
redeemedFunds: 200,
remainingFunds: 4800,
percentUtilized: 0.04,
offerType: EXEC_ED_OFFER_TYPE,
};

const defaultEnterpriseSubsidiesContextValue = {
isLoading: false,
};

const BudgetDetailPageWrapper = ({
enterpriseSubsidiesContextValue = defaultEnterpriseSubsidiesContextValue,
...rest
}) => (
<MemoryRouter initialEntries={['/test-enterprise/admin/learner-credit/1234']}>

<Provider store={store}>
<IntlProvider locale="en">
<EnterpriseSubsidiesContext.Provider value={enterpriseSubsidiesContextValue}>
<BudgetDetailPage {...rest} />
</EnterpriseSubsidiesContext.Provider>
</IntlProvider>
</Provider>
</MemoryRouter>
);

describe('<BudgetDetailPage />', () => {
describe('with enterprise offer', () => {
beforeEach(() => {
jest.clearAllMocks();
});

it('displays table on clicking view budget', async () => {
const mockOffer = {
id: mockEnterpriseOfferId,
name: mockOfferDisplayName,
start: '2022-01-01',
end: '2023-01-01',
};
useOfferSummary.mockReturnValue({
isLoading: false,
offerSummary: mockOfferSummary,
});
useOfferRedemptions.mockReturnValue({
isLoading: false,
offerRedemptions: {
itemCount: 0,
pageCount: 0,
results: [],
},
fetchOfferRedemptions: jest.fn(),
});
render(<BudgetDetailPageWrapper
enterpriseUUID={enterpriseUUID}
enterpriseSlug={enterpriseId}
offer={mockOffer}
/>);
expect(screen.getByText('Learner Credit Budget Detail'));
expect(screen.getByText('Overview'));
expect(screen.getByText('No results found'));
});
});
});
Loading