diff --git a/src/features/Instructors/InstructorsFilters/_test_/index.test.jsx b/src/features/Instructors/InstructorsFilters/_test_/index.test.jsx new file mode 100644 index 00000000..77d7f970 --- /dev/null +++ b/src/features/Instructors/InstructorsFilters/_test_/index.test.jsx @@ -0,0 +1,81 @@ +import React from 'react'; +import { render, fireEvent, act } from '@testing-library/react'; +import InstructorsFilters from 'features/Instructors/InstructorsFilters'; +import '@testing-library/jest-dom/extend-expect'; + +describe('InstructorsFilters Component', () => { + test('call service when apply filters', async () => { + const fetchData = jest.fn(); + const resetPagination = jest.fn(); + const { getByPlaceholderText, getByText } = render( + , + ); + + const button = getByText('Filters'); + await act(async () => { + fireEvent.click(button); + }); + + const nameInput = getByPlaceholderText('Enter Instructor Name'); + const emailInput = getByPlaceholderText('Enter Instructor Email'); + const classNameInput = getByPlaceholderText('Enter Class Name'); + const buttonApplyFilters = getByText('Apply Filters'); + + expect(nameInput).toBeInTheDocument(); + expect(emailInput).toBeInTheDocument(); + expect(classNameInput).toBeInTheDocument(); + + fireEvent.change(nameInput, { target: { value: 'Name' } }); + fireEvent.change(emailInput, { target: { value: 'name@example.com' } }); + fireEvent.change(classNameInput, { target: { value: 'CCX01' } }); + + expect(nameInput).toHaveValue('Name'); + expect(emailInput).toHaveValue('name@example.com'); + expect(classNameInput).toHaveValue('CCX01'); + + await act(async () => { + fireEvent.click(buttonApplyFilters); + }); + + expect(fetchData).toHaveBeenCalledTimes(1); + }); + + test('clear filters', async () => { + const fetchData = jest.fn(); + const resetPagination = jest.fn(); + const { getByPlaceholderText, getByText } = render( + , + ); + + const button = getByText('Filters'); + await act(async () => { + fireEvent.click(button); + }); + + const nameInput = getByPlaceholderText('Enter Instructor Name'); + const emailInput = getByPlaceholderText('Enter Instructor Email'); + const classNameInput = getByPlaceholderText('Enter Class Name'); + const buttonClearFilters = getByText('Clear'); + + expect(nameInput).toBeInTheDocument(); + expect(emailInput).toBeInTheDocument(); + expect(classNameInput).toBeInTheDocument(); + + fireEvent.change(nameInput, { target: { value: 'Name' } }); + fireEvent.change(emailInput, { target: { value: 'name@example.com' } }); + fireEvent.change(classNameInput, { target: { value: 'CCX01' } }); + + expect(nameInput).toHaveValue('Name'); + expect(emailInput).toHaveValue('name@example.com'); + expect(classNameInput).toHaveValue('CCX01'); + + await act(async () => { + fireEvent.click(buttonClearFilters); + }); + + expect(nameInput).toHaveValue(''); + expect(emailInput).toHaveValue(''); + expect(classNameInput).toHaveValue(''); + expect(resetPagination).toHaveBeenCalledTimes(1); + }); +}); diff --git a/src/features/Instructors/InstructorsFilters/index.jsx b/src/features/Instructors/InstructorsFilters/index.jsx new file mode 100644 index 00000000..8227f0a2 --- /dev/null +++ b/src/features/Instructors/InstructorsFilters/index.jsx @@ -0,0 +1,79 @@ +import React, { useState } from 'react'; +import { + DropdownButton, Form, Col, Button, +} from '@edx/paragon'; +import PropTypes from 'prop-types'; + +const initialFilterFormValues = { + instructorName: '', + instructorEmail: '', + ccxId: '', +}; + +const InstructorsFilters = ({ fetchData, resetPagination }) => { + const [filters, setFilters] = useState(initialFilterFormValues); + + const handleInputChange = (e) => { + setFilters({ + ...filters, + [e.target.name]: e.target.value.trim(), + }); + }; + + const handleApplyFilters = async () => { + fetchData(filters); + }; + + const handleCleanFilters = () => { + setFilters(initialFilterFormValues); + fetchData(); + resetPagination(); + }; + + return ( + + + + + + + + Apply Filters + Clear + + + + + ); +}; + +InstructorsFilters.propTypes = { + fetchData: PropTypes.func.isRequired, + resetPagination: PropTypes.func.isRequired, +}; + +export default InstructorsFilters; diff --git a/src/features/Instructors/InstructorsPage/index.jsx b/src/features/Instructors/InstructorsPage/index.jsx index 213960bd..87b40ede 100644 --- a/src/features/Instructors/InstructorsPage/index.jsx +++ b/src/features/Instructors/InstructorsPage/index.jsx @@ -7,6 +7,7 @@ import { Pagination, } from '@edx/paragon'; import InstructorsTable from 'features/Instructors/InstructorsTable'; +import InstructorsFilters from 'features/Instructors/InstructorsFilters'; import { getInstructorData } from 'features/Instructors/data/api'; import { @@ -30,11 +31,11 @@ const InstructorsPage = () => { const [state, dispatch] = useReducer(reducer, initialState); const [currentPage, setCurrentPage] = useState(1); - const fetchData = async () => { + const fetchData = async (filters) => { dispatch({ type: FETCH_INSTRUCTOR_DATA_REQUEST }); try { - const response = camelCaseObject(await getInstructorData(currentPage)); + const response = camelCaseObject(await getInstructorData(currentPage, filters)); dispatch({ type: FETCH_INSTRUCTOR_DATA_SUCCESS, payload: response.data }); } catch (error) { dispatch({ type: FETCH_INSTRUCTOR_DATA_FAILURE, payload: error }); @@ -52,9 +53,17 @@ const InstructorsPage = () => { fetchData(); }; + const resetPagination = () => { + setCurrentPage(1); + }; + return ( Instructors + + + + - +