generated from openedx/frontend-template-application
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: Add licenses page
- Loading branch information
Showing
15 changed files
with
354 additions
and
9 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -2,5 +2,5 @@ | |
|
||
.license-section { | ||
background-color: $color-white; | ||
padding: 2rem; | ||
padding: 2rem 0; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,68 @@ | ||
import React from 'react'; | ||
import axios from 'axios'; | ||
import { render, waitFor } from '@testing-library/react'; | ||
import LicensesPage from 'features/Licenses/LicensesPage'; | ||
import '@testing-library/jest-dom/extend-expect'; | ||
import { Provider } from 'react-redux'; | ||
import { initializeStore } from 'store'; | ||
|
||
let store; | ||
|
||
jest.mock('axios'); | ||
|
||
jest.mock('@edx/frontend-platform/logging', () => ({ | ||
logError: jest.fn(), | ||
})); | ||
|
||
const mockResponse = { | ||
data: { | ||
results: [ | ||
{ | ||
licenseName: 'License Name 1', | ||
purchasedSeats: 20, | ||
numberOfStudents: 6, | ||
numberOfPendingStudents: 11, | ||
}, | ||
{ | ||
licenseName: 'License Name 2', | ||
purchasedSeats: 10, | ||
numberOfStudents: 1, | ||
numberOfPendingStudents: 5, | ||
}, | ||
], | ||
count: 2, | ||
num_pages: 1, | ||
current_page: 1, | ||
}, | ||
}; | ||
|
||
describe('LicensesPage component', () => { | ||
beforeEach(() => { | ||
store = initializeStore(); | ||
}); | ||
|
||
test('renders licenses data components', () => { | ||
axios.get.mockResolvedValue(mockResponse); | ||
|
||
const component = render( | ||
<Provider store={store}> | ||
<LicensesPage /> | ||
</Provider>, | ||
); | ||
|
||
waitFor(() => { | ||
expect(component.container).toHaveTextContent('License Pool'); | ||
expect(component.container).toHaveTextContent('License Name 1'); | ||
expect(component.container).toHaveTextContent('License Name 2'); | ||
expect(component.container).toHaveTextContent('Purchased'); | ||
expect(component.container).toHaveTextContent('20'); | ||
expect(component.container).toHaveTextContent('10'); | ||
expect(component.container).toHaveTextContent('Enrolled'); | ||
expect(component.container).toHaveTextContent('6'); | ||
expect(component.container).toHaveTextContent('1'); | ||
expect(component.container).toHaveTextContent('Remaining'); | ||
expect(component.container).toHaveTextContent('11'); | ||
expect(component.container).toHaveTextContent('5'); | ||
}); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,55 @@ | ||
import React, { useEffect, useState } from 'react'; | ||
import { useDispatch, useSelector } from 'react-redux'; | ||
|
||
import Container from '@edx/paragon/dist/Container'; | ||
import LicensesTable from 'features/Licenses/LicensesTable'; | ||
import { Pagination } from '@edx/paragon'; | ||
|
||
import { fetchLicensesData } from 'features/Licenses/data'; | ||
import { updateCurrentPage } from 'features/Licenses/data/slice'; | ||
import { initialPage } from 'features/constants'; | ||
|
||
const LicensesPage = () => { | ||
const dispatch = useDispatch(); | ||
const stateInstitution = useSelector((state) => state.main.institution.data); | ||
const stateLicenses = useSelector((state) => state.licenses.table); | ||
const [currentPage, setCurrentPage] = useState(initialPage); | ||
|
||
let idInstitution = ''; | ||
// eslint-disable-next-line no-unused-expressions | ||
stateInstitution.length > 0 ? idInstitution = stateInstitution[0].id : idInstitution = ''; | ||
|
||
const handlePagination = (targetPage) => { | ||
setCurrentPage(targetPage); | ||
dispatch(updateCurrentPage(targetPage)); | ||
}; | ||
|
||
useEffect(() => { | ||
dispatch(fetchLicensesData(idInstitution)); | ||
}, [currentPage]); // eslint-disable-line react-hooks/exhaustive-deps | ||
|
||
return ( | ||
<Container size="xl" className="px-4"> | ||
<h2 className="title-page">License pool inventory</h2> | ||
<div className="page-content-container"> | ||
<LicensesTable | ||
data={stateLicenses.data} | ||
count={stateLicenses.count} | ||
/> | ||
{stateLicenses.numPages > 1 && ( | ||
<Pagination | ||
paginationLabel="paginationNavigation" | ||
pageCount={stateLicenses.numPages} | ||
currentPage={currentPage} | ||
onPageSelect={handlePagination} | ||
variant="reduced" | ||
className="mx-auto pagination-table" | ||
size="small" | ||
/> | ||
)} | ||
</div> | ||
</Container> | ||
); | ||
}; | ||
|
||
export default LicensesPage; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,95 @@ | ||
import MockAdapter from 'axios-mock-adapter'; | ||
import { getAuthenticatedHttpClient } from '@edx/frontend-platform/auth'; | ||
import { initializeMockApp } from '@edx/frontend-platform/testing'; | ||
import { fetchLicensesData } from 'features/Licenses/data'; | ||
import { updateCurrentPage } from 'features/Licenses/data/slice'; | ||
import { executeThunk } from 'test-utils'; | ||
import { initializeStore } from 'store'; | ||
|
||
let axiosMock; | ||
let store; | ||
|
||
describe('Licenses redux tests', () => { | ||
beforeEach(() => { | ||
initializeMockApp({ | ||
authenticatedUser: { | ||
userId: 1, | ||
username: 'testuser', | ||
administrator: true, | ||
roles: [], | ||
}, | ||
}); | ||
axiosMock = new MockAdapter(getAuthenticatedHttpClient()); | ||
|
||
store = initializeStore(); | ||
}); | ||
|
||
afterEach(() => { | ||
axiosMock.reset(); | ||
}); | ||
|
||
test('successful fetch licenses data', async () => { | ||
const licensesApiUrl = `${process.env.COURSE_OPERATIONS_API_V2_BASE_URL}/license-pool/?limit=true&institution_id=1`; | ||
const mockResponse = { | ||
results: [ | ||
{ | ||
licenseName: 'License Name 1', | ||
purchasedSeats: 20, | ||
numberOfStudents: 6, | ||
numberOfPendingStudents: 11, | ||
}, | ||
{ | ||
licenseName: 'License Name 2', | ||
purchasedSeats: 10, | ||
numberOfStudents: 1, | ||
numberOfPendingStudents: 5, | ||
}, | ||
], | ||
count: 2, | ||
num_pages: 1, | ||
current_page: 1, | ||
}; | ||
axiosMock.onGet(licensesApiUrl) | ||
.reply(200, mockResponse); | ||
|
||
expect(store.getState().licenses.table.status) | ||
.toEqual('loading'); | ||
|
||
await executeThunk(fetchLicensesData(1), store.dispatch, store.getState); | ||
|
||
expect(store.getState().licenses.table.data) | ||
.toEqual(mockResponse.results); | ||
|
||
expect(store.getState().licenses.table.status) | ||
.toEqual('success'); | ||
}); | ||
|
||
test('failed fetch licenses data', async () => { | ||
const licensesApiUrl = `${process.env.COURSE_OPERATIONS_API_V2_BASE_URL}/license-pool/?limit=false&institution_id=1`; | ||
axiosMock.onGet(licensesApiUrl) | ||
.reply(500); | ||
|
||
expect(store.getState().licenses.table.status) | ||
.toEqual('loading'); | ||
|
||
await executeThunk(fetchLicensesData(1), store.dispatch, store.getState); | ||
|
||
expect(store.getState().licenses.table.data) | ||
.toEqual([]); | ||
|
||
expect(store.getState().licenses.table.status) | ||
.toEqual('error'); | ||
}); | ||
|
||
test('update current page', () => { | ||
const newPage = 2; | ||
const intialState = store.getState().courses.table; | ||
const expectState = { | ||
...intialState, | ||
currentPage: newPage, | ||
}; | ||
|
||
store.dispatch(updateCurrentPage(newPage)); | ||
expect(store.getState().licenses.table).toEqual(expectState); | ||
}); | ||
}); |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,2 @@ | ||
export { reducer } from 'features/Licenses/data/slice'; | ||
export { fetchLicensesData } from 'features/Licenses/data/thunks'; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,46 @@ | ||
/* eslint-disable no-param-reassign */ | ||
import { createSlice } from '@reduxjs/toolkit'; | ||
import { RequestStatus } from 'features/constants'; | ||
|
||
const initialState = { | ||
table: { | ||
currentPage: 1, | ||
data: [], | ||
status: RequestStatus.LOADING, | ||
error: null, | ||
numPages: 0, | ||
count: 0, | ||
}, | ||
}; | ||
|
||
export const licensesSlice = createSlice({ | ||
name: 'licenses', | ||
initialState, | ||
reducers: { | ||
updateCurrentPage: (state, { payload }) => { | ||
state.table.currentPage = payload; | ||
}, | ||
fetchLicensesDataRequest: (state) => { | ||
state.table.status = RequestStatus.LOADING; | ||
}, | ||
fetchLicensesDataSuccess: (state, { payload }) => { | ||
const { results, count, numPages } = payload; | ||
state.table.status = RequestStatus.SUCCESS; | ||
state.table.data = results; | ||
state.table.numPages = numPages; | ||
state.table.count = count; | ||
}, | ||
fetchLicensesDataFailed: (state) => { | ||
state.table.status = RequestStatus.ERROR; | ||
}, | ||
}, | ||
}); | ||
|
||
export const { | ||
updateCurrentPage, | ||
fetchLicensesDataRequest, | ||
fetchLicensesDataSuccess, | ||
fetchLicensesDataFailed, | ||
} = licensesSlice.actions; | ||
|
||
export const { reducer } = licensesSlice; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,26 @@ | ||
import { logError } from '@edx/frontend-platform/logging'; | ||
import { camelCaseObject } from '@edx/frontend-platform'; | ||
|
||
import { getLicensesByInstitution } from 'features/Common/data/api'; | ||
import { | ||
fetchLicensesDataRequest, | ||
fetchLicensesDataSuccess, | ||
fetchLicensesDataFailed, | ||
} from 'features/Licenses/data/slice'; | ||
|
||
function fetchLicensesData(id) { | ||
return async (dispatch) => { | ||
dispatch(fetchLicensesDataRequest()); | ||
try { | ||
const response = camelCaseObject(await getLicensesByInstitution(id, true)); | ||
dispatch(fetchLicensesDataSuccess(response.data)); | ||
} catch (error) { | ||
dispatch(fetchLicensesDataFailed()); | ||
logError(error); | ||
} | ||
}; | ||
} | ||
|
||
export { | ||
fetchLicensesData, | ||
}; |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Oops, something went wrong.