Skip to content

Commit

Permalink
feat: Add instructors component
Browse files Browse the repository at this point in the history
  • Loading branch information
AuraAlba committed Oct 12, 2023
1 parent 7ba165f commit 524b891
Show file tree
Hide file tree
Showing 8 changed files with 250 additions and 2 deletions.
45 changes: 45 additions & 0 deletions src/features/Instructors/AddInstructors/_test_/index.test.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
import React from 'react';
import axios from 'axios';
import { render, fireEvent, act } from '@testing-library/react';
import AddInstructors from 'features/Instructors/AddInstructors';
import '@testing-library/jest-dom/extend-expect';

jest.mock('axios');

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

const mockResponse = {
data: [
{
classId: 'CCX1',
className: 'CCX 1',
masterCourseName: 'Master1',
},
{
classId: 'CCX2',
className: 'CCX 2',
masterCourseName: 'Master2',
},
],
};

describe('Add instructor component', () => {
test('Render and load modal', async () => {
axios.get.mockResolvedValue(mockResponse);

const { getByPlaceholderText, getByText } = render(
<AddInstructors />,
);
const button = getByText('Add Instructor');
await act(async () => {
fireEvent.click(button);
});

const instructorInfoInput = getByPlaceholderText('Enter Username or Email of the instructor');
const ccxSelect = getByText('Select Class Name');
expect(instructorInfoInput).toBeInTheDocument();
expect(ccxSelect).toBeInTheDocument();
});
});
53 changes: 53 additions & 0 deletions src/features/Instructors/AddInstructors/_test_/reducer.test.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,53 @@
import {
FETCH_CCX_LIST_FAILURE,
FETCH_CCX_LIST_REQUEST,
FETCH_CCX_LIST_SUCCESS,
} from 'features/Instructors/actionTypes';
import { RequestStatus } from 'features/constants';
import reducer from 'features/Instructors/InstructorsPage/reducer';

describe('Instructor page reducers', () => {
const initialState = {
data: [],
error: null,
};

test('should handle FETCH_CCX_LIST_REQUEST', () => {
const state = {
...initialState,
status: RequestStatus.LOADING,
};
const action = {
type: FETCH_CCX_LIST_REQUEST,
};
expect(reducer(state, action)).toEqual(state);
});

test('should handle FETCH_CCX_LIST_SUCCESS', () => {
const state = {
...initialState,
status: RequestStatus.SUCCESS,
count: 0,
};
const action = {
type: FETCH_CCX_LIST_SUCCESS,
payload: {
data: [],
},
};
expect(reducer(state, action)).toEqual(state);
});

test('should handle FETCH_CCX_LIST_FAILURE', () => {
const state = {
...initialState,
status: RequestStatus.ERROR,
error: '',
};
const action = {
type: FETCH_CCX_LIST_FAILURE,
payload: '',
};
expect(reducer(state, action)).toEqual(state);
});
});
107 changes: 107 additions & 0 deletions src/features/Instructors/AddInstructors/index.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,107 @@
import React, { useState, useReducer, useEffect } from 'react';
import {
Button, FormGroup, ModalDialog, useToggle, Form,
} from '@edx/paragon';
import { getCCXList } from 'features/Instructors/data/api';
import reducer from 'features/Instructors/AddInstructors/reducer';
import { logError } from '@edx/frontend-platform/logging';
import { camelCaseObject } from '@edx/frontend-platform';

import { FETCH_CCX_LIST_FAILURE, FETCH_CCX_LIST_REQUEST, FETCH_CCX_LIST_SUCCESS } from 'features/Instructors/actionTypes';
import { RequestStatus } from 'features/constants';

const initialState = {
data: [],
status: RequestStatus.SUCCESS,
error: null,
};

const addInstructorState = {
instructorInfo: '',
ccxId: '',
ccxName: '',
};

const AddInstructors = () => {
const [state, dispatch] = useReducer(reducer, initialState);
const [isOpen, open, close] = useToggle(false);
const [addInstructorInfo, setAddInstructorInfo] = useState(addInstructorState);

const fetchData = async () => {
dispatch({ type: FETCH_CCX_LIST_REQUEST });

try {
const response = camelCaseObject(await getCCXList());
dispatch({ type: FETCH_CCX_LIST_SUCCESS, payload: response.data });
} catch (error) {
dispatch({ type: FETCH_CCX_LIST_FAILURE, payload: error });
logError(error);
}
};

const handleInstructorInput = (e) => {
setAddInstructorInfo({
...addInstructorInfo,
instructorInfo: e.target.value.trim(),
});
};

const handleCcxSelect = (e) => {
const select = e.target;
setAddInstructorInfo({
...addInstructorInfo,
ccxId: select.value,
ccxName: select.options[select.selectedIndex].text,
});
};

useEffect(() => {
fetchData();
}, []);

return (
<>
<Button variant="primary" onClick={open} size="sm">
Add Instructor
</Button>
<ModalDialog
title="Add Instructor"
isOpen={isOpen}
onClose={close}
hasCloseButton
>
<ModalDialog.Header>
<ModalDialog.Title>
Add Instructor
</ModalDialog.Title>
</ModalDialog.Header>
<ModalDialog.Body>
<FormGroup>
<Form.Control
as="select"
floatingLabel="Select Class Name"
className="my-4 mr-0"
onChange={handleCcxSelect}
id="selectCcx"
>
{state.data.map((ccx) => <option value={ccx.classId}>{ccx.className}</option>)}
</Form.Control>
<Form.Control
type="text"
placeholder="Enter Username or Email of the instructor"
floatingLabel="Username or Email"
value={addInstructorInfo.instructorInfo}
onChange={handleInstructorInput}
className="my-4 mr-0"
/>
<div className="d-flex justify-content-end">
<Button>Add</Button>
</div>
</FormGroup>
</ModalDialog.Body>
</ModalDialog>
</>
);
};

export default AddInstructors;
30 changes: 30 additions & 0 deletions src/features/Instructors/AddInstructors/reducer.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
import {
FETCH_CCX_LIST_FAILURE,
FETCH_CCX_LIST_REQUEST,
FETCH_CCX_LIST_SUCCESS,
} from 'features/Instructors/actionTypes';
import { RequestStatus } from 'features/constants';

const reducer = (state, action) => {
switch (action.type) {
case FETCH_CCX_LIST_REQUEST:
return { ...state, status: RequestStatus.LOADING };
case FETCH_CCX_LIST_SUCCESS: {
return {
...state,
status: RequestStatus.SUCCESS,
data: action.payload,
};
}
case FETCH_CCX_LIST_FAILURE:
return {
...state,
status: RequestStatus.ERROR,
error: action.payload,
};
default:
return state;
}
};

export default reducer;
2 changes: 1 addition & 1 deletion src/features/Instructors/InstructorsFilters/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -31,7 +31,7 @@ const InstructorsFilters = ({ fetchData, resetPagination }) => {
};

return (
<DropdownButton title="Filters" variant="outline-primary">
<DropdownButton title="Filters" variant="outline-primary" size="sm" className="mr-3">
<Form className="row justify-content-center px-3 py-2">
<Form.Group as={Col} className="mb-0">
<Form.Control
Expand Down
3 changes: 2 additions & 1 deletion src/features/Instructors/InstructorsPage/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import {
} from '@edx/paragon';
import InstructorsTable from 'features/Instructors/InstructorsTable';
import InstructorsFilters from 'features/Instructors/InstructorsFilters';
import AddInstructors from 'features/Instructors/AddInstructors';

import { getInstructorData } from 'features/Instructors/data/api';
import {
Expand Down Expand Up @@ -62,8 +63,8 @@ const InstructorsPage = () => {
<h2>Instructors</h2>
<div className="d-flex justify-content-end">
<InstructorsFilters fetchData={fetchData} resetPagination={resetPagination} />
<AddInstructors />
</div>

<InstructorsTable
data={state.data}
count={state.count}
Expand Down
4 changes: 4 additions & 0 deletions src/features/Instructors/actionTypes.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,3 +2,7 @@ export const FETCH_INSTRUCTOR_DATA_REQUEST = 'FETCH_INSTRUCTOR_DATA_REQUEST';
export const FETCH_INSTRUCTOR_DATA_SUCCESS = 'FETCH_INSTRUCTOR_DATA_SUCCESS';
export const FETCH_INSTRUCTOR_DATA_FAILURE = 'FETCH_INSTRUCTOR_DATA_FAILURE';
export const UPDATE_CURRENT_PAGE = 'UPDATE_CURRENT_PAGE';

export const FETCH_CCX_LIST_REQUEST = 'FETCH_CCX_LIST_REQUEST';
export const FETCH_CCX_LIST_SUCCESS = 'FETCH_CCX_LIST_SUCCESS';
export const FETCH_CCX_LIST_FAILURE = 'FETCH_CCX_LIST_FAILURE';
8 changes: 8 additions & 0 deletions src/features/Instructors/data/api.js
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,14 @@ function getInstructorData(page, filters) {
);
}

function getCCXList() {
const apiV2BaseUrl = getConfig().COURSE_OPERATIONS_API_V2_BASE_URL;
return getAuthenticatedHttpClient().get(
`${apiV2BaseUrl}/classes?limit=false`,
);
}

export {
getInstructorData,
getCCXList,
};

0 comments on commit 524b891

Please sign in to comment.