Skip to content

Commit

Permalink
feat: Add instructor assignment section
Browse files Browse the repository at this point in the history
  • Loading branch information
AuraAlba committed Jan 26, 2024
1 parent 979f585 commit 691b074
Show file tree
Hide file tree
Showing 25 changed files with 421 additions and 91 deletions.
1 change: 1 addition & 0 deletions .eslintignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,4 @@ dist/
node_modules/
jest.config.js
.eslintrc.js
test-utils.jsx
1 change: 0 additions & 1 deletion .eslintrc.js
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
// eslint-disable-next-line import/no-extraneous-dependencies
const { createConfig } = require('@edx/frontend-build');

module.exports = createConfig('eslint', {
Expand Down
19 changes: 10 additions & 9 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion package.json
Original file line number Diff line number Diff line change
Expand Up @@ -42,7 +42,7 @@
"@fortawesome/react-fontawesome": "^0.2.0",
"@reduxjs/toolkit": "^1.9.5",
"core-js": "3.31.0",
"moment": "^2.29.4",
"date-fns": "^3.3.1",
"prop-types": "15.8.1",
"react": "16.14.0",
"react-dom": "16.14.0",
Expand Down
1 change: 1 addition & 0 deletions src/assets/colors.scss
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@ $color-black: #020917;
$black-80: #333;
$color-white: #fefefe;
$color-gray: #60646d;
$gray-70: #666666;
$gray-60: #808080;
$gray-20: #dfe1e1;
$color-pink: #ffecf0;
Expand Down
32 changes: 29 additions & 3 deletions src/features/Common/data/_test_/api.test.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,9 @@
import { getAuthenticatedHttpClient } from '@edx/frontend-platform/auth';
import { getCoursesByInstitution, getLicensesByInstitution } from 'features/Common/data/api';
import {
getCoursesByInstitution,
getLicensesByInstitution,
getClassesByInstitution,
} from 'features/Common/data/api';

jest.mock('@edx/frontend-platform/auth', () => ({
getAuthenticatedHttpClient: jest.fn(),
Expand All @@ -13,6 +17,7 @@ jest.mock('@edx/frontend-platform', () => ({
}));

describe('Common api services', () => {
const COURSE_OPERATIONS_API_V2 = 'http://localhost:18000/pearson_course_operation/api/v2';
test('should call getCoursesByInstitution with the correct parameters', () => {
const httpClientMock = {
get: jest.fn(),
Expand All @@ -30,7 +35,7 @@ describe('Common api services', () => {

expect(httpClientMock.get).toHaveBeenCalledTimes(1);
expect(httpClientMock.get).toHaveBeenCalledWith(
'http://localhost:18000/pearson_course_operation/api/v2/courses/?limit=true&institution_id=1',
`${COURSE_OPERATIONS_API_V2}/courses/?limit=true&institution_id=1`,
{ params: { page } },
);
});
Expand All @@ -51,7 +56,28 @@ describe('Common api services', () => {

expect(httpClientMock.get).toHaveBeenCalledTimes(1);
expect(httpClientMock.get).toHaveBeenCalledWith(
'http://localhost:18000/pearson_course_operation/api/v2/license-pool/?limit=true&institution_id=1',
`${COURSE_OPERATIONS_API_V2}/license-pool/?limit=true&institution_id=1`,
);
});

test('should call getClassesByInstitution with the correct parameters', () => {
const httpClientMock = {
get: jest.fn(),
};

const institutionId = 1;
const courseName = 'ccx1';

getAuthenticatedHttpClient.mockReturnValue(httpClientMock);

getClassesByInstitution(institutionId, courseName);

expect(getAuthenticatedHttpClient).toHaveBeenCalledTimes(3);
expect(getAuthenticatedHttpClient).toHaveBeenCalledWith();

expect(httpClientMock.get).toHaveBeenCalledTimes(1);
expect(httpClientMock.get).toHaveBeenCalledWith(
`${COURSE_OPERATIONS_API_V2}/classes/?limit=false&institution_id=1&course_name=ccx1&instructors=`,
);
});
});
10 changes: 10 additions & 0 deletions src/features/Common/data/api.js
Original file line number Diff line number Diff line change
Expand Up @@ -18,7 +18,17 @@ function getLicensesByInstitution(institutionId, limit) {
);
}

function getClassesByInstitution(institutionId, courseName, limit = false, instructorsList = '') {
const encodedCourseName = encodeURIComponent(courseName);

return getAuthenticatedHttpClient().get(
`${getConfig().COURSE_OPERATIONS_API_V2_BASE_URL}/classes`
+ `/?limit=${limit}&institution_id=${institutionId}&course_name=${encodedCourseName}&instructors=${instructorsList}`,
);
}

export {
getCoursesByInstitution,
getLicensesByInstitution,
getClassesByInstitution,
};
56 changes: 41 additions & 15 deletions src/features/Dashboard/DashboardPage/_test_/index.test.jsx
Original file line number Diff line number Diff line change
@@ -1,34 +1,60 @@
import React from 'react';
import { render } from '@testing-library/react';
import DashboardPage from 'features/Dashboard/DashboardPage';
import '@testing-library/jest-dom/extend-expect';
import { Provider } from 'react-redux';
import { initializeStore } from 'store';

let store;

jest.mock('axios');
import { renderWithProviders } from 'test-utils';

jest.mock('@edx/frontend-platform/logging', () => ({
logError: jest.fn(),
}));

describe('DashboardPage component', () => {
beforeEach(() => {
store = initializeStore();
});
const mockStore = {
dashboard: {
tableLicense: {
data: [
{
licenseName: 'License Name 1',
purchasedSeats: 20,
numberOfStudents: 6,
numberOfPendingStudents: 11,
},
],
},
classes: {
data: [
{
classId: 'ccx-v1:demo+demo1+2020+ccx1',
className: 'ccx 1',
masterCourseName: 'Demo Course 1',
instructors: [],
numberOfStudents: 0,
numberOfPendingStudents: 0,
maxStudents: 20,
startDate: '2024-01-23T21:50:51Z',
endDate: null,
},
],
},
},
};

const component = renderWithProviders(
<DashboardPage />,
{ preloadedState: mockStore },
);

test('renders components', () => {
const { getByText } = render(
<Provider store={store}>
<DashboardPage />
</Provider>,
);
const { getByText } = component;

expect(getByText('This week')).toBeInTheDocument();
expect(getByText('Next week')).toBeInTheDocument();
expect(getByText('Next month')).toBeInTheDocument();
expect(getByText('New students registered')).toBeInTheDocument();
expect(getByText('Classes scheduled')).toBeInTheDocument();
expect(getByText('License inventory')).toBeInTheDocument();
expect(getByText('Instructor assignment')).toBeInTheDocument();
expect(getByText('ccx 1')).toBeInTheDocument();
expect(getByText('Demo Course 1')).toBeInTheDocument();
expect(getByText('License Name 1')).toBeInTheDocument();
});
});
26 changes: 18 additions & 8 deletions src/features/Dashboard/DashboardPage/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,11 @@ import React, { useEffect, useState } from 'react';
import { useSelector, useDispatch } from 'react-redux';
import { useHistory } from 'react-router-dom';

import { Container } from '@edx/paragon';
import { Container, Col, Row } from '@edx/paragon';
import StudentsMetrics from 'features/Students/StudentsMetrics';
import LicensesTable from 'features/Licenses/LicensesTable';
import { Button } from 'react-paragon-topaz';
import InstructorAssignSection from 'features/Dashboard/InstructorAssignSection';

import { fetchLicensesData } from 'features/Dashboard/data';
import { updateActiveTab } from 'features/Main/data/slice';
Expand Down Expand Up @@ -50,13 +51,22 @@ const DashboardPage = () => {
{stateInstitution.length === 1 ? `Welcome to ${stateInstitution[0].name}` : 'Select an institution'}
</h2>
<StudentsMetrics />
<div className="license-section">
<div className="d-flex justify-content-between px-4">
<h3>License inventory</h3>
<Button onClick={handleViewAllLicenses} variant="outline-primary">View All</Button>
</div>
<LicensesTable data={dataTableLicense} />
</div>
<Row>
<Col lg="9" xs="12">
<div className="license-section">
<div className="d-flex justify-content-between px-4">
<h3>License inventory</h3>
<Button onClick={handleViewAllLicenses} variant="outline-primary">View All</Button>
</div>
<LicensesTable data={dataTableLicense} />
</div>
</Col>
<Col lg="3" xs="12">
<div className="instructor-assign-section">
<InstructorAssignSection />
</div>
</Col>
</Row>
</Container>
);
};
Expand Down
10 changes: 10 additions & 0 deletions src/features/Dashboard/DashboardPage/index.scss
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,13 @@
background-color: $color-white;
padding: 2rem 0;
}

.instructor-assign-section {
background-color: $color-white;
}

.license-section,
.instructor-assign-section {
box-shadow: 0px 3px 12px 0px rgba(0, 0, 0, 0.16);
border-radius: 0.375rem;
}
33 changes: 33 additions & 0 deletions src/features/Dashboard/InstructorAssignSection/ClassCard.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import React from 'react';
import { format } from 'date-fns';
import PropTypes from 'prop-types';

import { Button } from 'react-paragon-topaz';

import 'features/Dashboard/InstructorAssignSection/index.scss';

const ClassCard = ({ data }) => {
const fullDate = format(new Date(data.startDate), 'PP');

return (
<div className="class-card-container">
<h4>{data?.className}</h4>
<p className="course-name">{data?.masterCourseName}</p>
<p className="date"><i className="fa-sharp fa-regular fa-calendar-day" />{fullDate}</p>
<Button variant="outline-primary" size="sm">
<i className="fa-regular fa-chalkboard-user" />
Assign instructor
</Button>
</div>
);
};

ClassCard.propTypes = {
data: PropTypes.arrayOf(PropTypes.shape([])),
};

ClassCard.defaultProps = {
data: [],
};

export default ClassCard;
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
import React from 'react';
import InstructorAssignSection from 'features/Dashboard/InstructorAssignSection';
import '@testing-library/jest-dom/extend-expect';
import { renderWithProviders } from 'test-utils';

jest.mock('@edx/frontend-platform/logging', () => ({
logError: jest.fn(),
}));

describe('Instructor Assign component', () => {
const mockStore = {
dashboard: {
classes: {
data: [
{
classId: 'ccx-v1:demo+demo1+2020+ccx1',
className: 'ccx 1',
masterCourseName: 'Demo Course 1',
instructors: [],
numberOfStudents: 0,
numberOfPendingStudents: 0,
maxStudents: 20,
startDate: '2024-01-23T21:50:51Z',
endDate: null,
},
],
},
},
};
const component = renderWithProviders(
<InstructorAssignSection />,
{ preloadedState: mockStore },
);

test('renders components', () => {
const { getByText } = component;

expect(getByText('Instructor assignment')).toBeInTheDocument();
expect(getByText('ccx 1')).toBeInTheDocument();
expect(getByText('Demo Course 1')).toBeInTheDocument();
expect(getByText('Jan 23, 2024')).toBeInTheDocument();
expect(getByText('Assign instructor')).toBeInTheDocument();
});
});
Loading

0 comments on commit 691b074

Please sign in to comment.