From 522d0acb9043a918428e50f034e1b2c035c27b1d Mon Sep 17 00:00:00 2001 From: Aura Alba Date: Tue, 19 Nov 2024 09:10:50 -0500 Subject: [PATCH] feat: change filter component in courses page --- package-lock.json | 8 +- package.json | 2 +- .../CoursesFilters/_test_/index.test.jsx | 34 ++++---- src/features/Courses/CoursesFilters/index.jsx | 84 +++++++++---------- src/features/constants.js | 27 ++++++ 5 files changed, 86 insertions(+), 69 deletions(-) diff --git a/package-lock.json b/package-lock.json index 4b5f900d..6692a6ac 100644 --- a/package-lock.json +++ b/package-lock.json @@ -25,7 +25,7 @@ "react": "16.14.0", "react-dom": "16.14.0", "react-intl": "^5.25.1", - "react-paragon-topaz": "1.19.1", + "react-paragon-topaz": "1.20.0", "react-redux": "^7.2.9", "react-router": "5.2.1", "react-router-dom": "5.3.0", @@ -17174,9 +17174,9 @@ } }, "node_modules/react-paragon-topaz": { - "version": "1.19.1", - "resolved": "https://registry.npmjs.org/react-paragon-topaz/-/react-paragon-topaz-1.19.1.tgz", - "integrity": "sha512-vYYqud4M1PkCAIdqoCBCQ0z3a7gd8YN6KBzeZw+Nx0lUrS8aqTKZ9WBX6aJvUj+mLwSGLBUInppsXlXJryrNyA==", + "version": "1.20.0", + "resolved": "https://registry.npmjs.org/react-paragon-topaz/-/react-paragon-topaz-1.20.0.tgz", + "integrity": "sha512-LxdkTWzgWe4FJ/wYXvaEE6lbFOZYjDPQ6KVzkgTYZ9BGi6W4iWL8gt6p90L8gYWdoPvRn3ypMasYbPn3o9CFrg==", "dependencies": { "@babel/runtime": "7.25.6", "@edx/frontend-platform": "4.5.1", diff --git a/package.json b/package.json index df359612..0875c546 100644 --- a/package.json +++ b/package.json @@ -50,7 +50,7 @@ "react": "16.14.0", "react-dom": "16.14.0", "react-intl": "^5.25.1", - "react-paragon-topaz": "1.19.1", + "react-paragon-topaz": "1.20.0", "react-redux": "^7.2.9", "react-router": "5.2.1", "react-router-dom": "5.3.0", diff --git a/src/features/Courses/CoursesFilters/_test_/index.test.jsx b/src/features/Courses/CoursesFilters/_test_/index.test.jsx index b1c75240..058342f4 100644 --- a/src/features/Courses/CoursesFilters/_test_/index.test.jsx +++ b/src/features/Courses/CoursesFilters/_test_/index.test.jsx @@ -1,17 +1,17 @@ /* eslint-disable react/prop-types */ import React from 'react'; -import { fireEvent, act } from '@testing-library/react'; +import { fireEvent } from '@testing-library/react'; import CoursesFilters from 'features/Courses/CoursesFilters'; import '@testing-library/jest-dom/extend-expect'; import { initializeMockApp } from '@edx/frontend-platform/testing'; import { renderWithProviders } from 'test-utils'; +import { allResultsOption } from 'features/constants'; jest.mock('react-select', () => function reactSelect({ options, valueR, onChange }) { function handleChange(event) { - const option = options.find( - (optionR) => optionR.value === event.currentTarget.value, - ); - onChange(option); + onChange({ id: event.currentTarget.value }); + + return event; } return ( @@ -69,15 +69,15 @@ describe('CoursesFilters Component', () => { }); }); - test('call service when apply filters', async () => { - const resetPagination = jest.fn(); + test('should select a course', async () => { const { getByText, getByTestId } = renderWithProviders( - , + , { preloadedState: mockStore }, ); const courseSelect = getByTestId('select'); - const buttonApplyFilters = getByText('Apply'); + + expect(getByText('Find a primary course')).toBeInTheDocument(); expect(courseSelect).toBeInTheDocument(); fireEvent.change(courseSelect, { @@ -85,27 +85,21 @@ describe('CoursesFilters Component', () => { }); expect(getByText('Demo Course 1')).toBeInTheDocument(); - await act(async () => { - fireEvent.click(buttonApplyFilters); - }); }); - test('clear filters', async () => { - const resetPagination = jest.fn(); + test('Should have option for all results ', async () => { const { getByText, getByTestId } = renderWithProviders( - , + , ); const courseSelect = getByTestId('select'); - const buttonClearFilters = getByText('Reset'); expect(courseSelect).toBeInTheDocument(); expect(courseSelect).toBeInTheDocument(); fireEvent.change(courseSelect, { - target: { value: 'Demo Course 1' }, - }); - await act(async () => { - fireEvent.click(buttonClearFilters); + target: { value: allResultsOption.value }, }); + + expect(getByText('Show all search results')).toBeInTheDocument(); }); }); diff --git a/src/features/Courses/CoursesFilters/index.jsx b/src/features/Courses/CoursesFilters/index.jsx index c9b2c0a4..da8bdacb 100644 --- a/src/features/Courses/CoursesFilters/index.jsx +++ b/src/features/Courses/CoursesFilters/index.jsx @@ -1,44 +1,33 @@ import React, { useState, useEffect } from 'react'; import { useDispatch, useSelector } from 'react-redux'; -import PropTypes from 'prop-types'; import { Col, Form } from '@edx/paragon'; -import { Select, Button } from 'react-paragon-topaz'; -import { logError } from '@edx/frontend-platform/logging'; +import { Select } from 'react-paragon-topaz'; import { updateFilters, updateCurrentPage } from 'features/Courses/data/slice'; import { fetchCoursesData, fetchCoursesOptionsData } from 'features/Courses/data/thunks'; -import { initialPage } from 'features/constants'; +import { initialPage, styleFirstOption, allResultsOption } from 'features/constants'; -const CoursesFilters = ({ resetPagination }) => { +const CoursesFilters = () => { const dispatch = useDispatch(); const selectedInstitution = useSelector((state) => state.main.selectedInstitution); const courses = useSelector((state) => state.courses.selectOptions); const [courseOptions, setCourseOptions] = useState([]); const [courseSelected, setCourseSelected] = useState(null); + const [inputCourse, setInputCourse] = useState(''); - const isButtonDisabled = courseSelected === null; - - const handleCoursesFilter = async (e) => { - e.preventDefault(); - const form = e.target; - const formData = new FormData(form); - const formJson = Object.fromEntries(formData.entries()); - dispatch(updateFilters(formJson)); - try { - dispatch(updateCurrentPage(initialPage)); - dispatch(fetchCoursesData(selectedInstitution.id, initialPage, formJson)); - } catch (error) { - logError(error); + const filterOptions = (option, input) => { + if (input) { + return option.label.toLowerCase().includes(input) || option.value === allResultsOption.value; } + return true; }; - const handleCleanFilters = () => { - dispatch(fetchCoursesData(selectedInstitution.id)); - resetPagination(); - setCourseSelected(null); - dispatch(updateFilters({})); + const handleInputChange = (value, { action }) => { + if (action === 'input-change') { + setInputCourse(value); + } }; useEffect(() => { @@ -57,37 +46,48 @@ const CoursesFilters = ({ resetPagination }) => { })) : []; - setCourseOptions(options); + setCourseOptions([allResultsOption, ...options]); }, [courses]); + useEffect(() => { + if (Object.keys(selectedInstitution).length > 0) { + const params = {}; + + if (courseSelected) { + params.course_name = courseSelected.value === allResultsOption.value + ? inputCourse : courseSelected.value; + } + dispatch(fetchCoursesData(selectedInstitution.id, initialPage, params)); + setInputCourse(''); + dispatch(updateFilters(params)); + dispatch(updateCurrentPage(initialPage)); + } + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [courseSelected, selectedInstitution]); + return (
-

Find a course

-
+

Find a primary course

+ - +