feat: Add courseware search results filter container (#1225)
This commit is contained in:
@@ -0,0 +1,50 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
|
||||
import { Tabs, Tab } from '@edx/paragon';
|
||||
|
||||
import CoursewareSearchResultPropType from './CoursewareSearchResult.PropTypeDefinition';
|
||||
import CoursewareSearchResults from './CoursewareSearchResults';
|
||||
|
||||
export const filteredResultsBySelection = ({ filterKey = 'all', results = [] }) => {
|
||||
if (['document', 'video', 'text'].includes(filterKey)) {
|
||||
return results.filter(result => result?.type?.toLowerCase() === filterKey);
|
||||
}
|
||||
|
||||
return results || [];
|
||||
};
|
||||
|
||||
const tabConfiguration = [
|
||||
{ eventKey: 'all', title: 'All content' },
|
||||
{ eventKey: 'document', title: 'Course outline' },
|
||||
{ eventKey: 'text', title: 'Text' },
|
||||
{ eventKey: 'video', title: 'Video' },
|
||||
];
|
||||
|
||||
export const CoursewareSearchResultsFilter = ({ intl, results }) => {
|
||||
if (!results || !results.length) { return null; }
|
||||
|
||||
return (
|
||||
<Tabs id="courseware-search-results-tabs" data-testid="courseware-search-results-tabs" variant="tabs" defaultActiveKey="all">
|
||||
{tabConfiguration.map((tab) => (
|
||||
<Tab {...tab} key={tab.eventKey}>
|
||||
<CoursewareSearchResults
|
||||
intl={intl}
|
||||
results={filteredResultsBySelection({ filterKey: tab.eventKey, results })}
|
||||
/>
|
||||
</Tab>
|
||||
))}
|
||||
</Tabs>
|
||||
);
|
||||
};
|
||||
|
||||
CoursewareSearchResultsFilter.propTypes = {
|
||||
intl: intlShape.isRequired,
|
||||
results: PropTypes.arrayOf(CoursewareSearchResultPropType),
|
||||
};
|
||||
|
||||
CoursewareSearchResultsFilter.defaultProps = {
|
||||
results: [],
|
||||
};
|
||||
|
||||
export default injectIntl(CoursewareSearchResultsFilter);
|
||||
@@ -0,0 +1,85 @@
|
||||
import React from 'react';
|
||||
import {
|
||||
initializeMockApp,
|
||||
render,
|
||||
screen,
|
||||
waitFor,
|
||||
} from '../../setupTest';
|
||||
import { CoursewareSearchResultsFilter, filteredResultsBySelection } from './CoursewareResultsFilter';
|
||||
|
||||
const mockResults = [
|
||||
{ type: 'video', title: 'video_title' },
|
||||
{ type: 'video', title: 'video_title2' },
|
||||
{ type: 'document', title: 'document_title' },
|
||||
{ type: 'text', title: 'text_title1' },
|
||||
{ type: 'text', title: 'text_title2' },
|
||||
{ type: 'text', title: 'text_title3' },
|
||||
];
|
||||
|
||||
describe('CoursewareSearchResultsFilter', () => {
|
||||
beforeAll(initializeMockApp);
|
||||
|
||||
describe('filteredResultsBySelection', () => {
|
||||
it('returns a no values array when no results are provided', () => {
|
||||
const results = filteredResultsBySelection({ results: [] });
|
||||
|
||||
expect(results.length).toEqual(0);
|
||||
});
|
||||
|
||||
it('returns all values when no key value is provided', () => {
|
||||
const results = filteredResultsBySelection({ results: mockResults });
|
||||
|
||||
expect(results.length).toEqual(mockResults.length);
|
||||
});
|
||||
|
||||
it('returns all values when the key value "all" is provided', () => {
|
||||
const results = filteredResultsBySelection({ filterKey: 'all', results: mockResults });
|
||||
|
||||
expect(results.length).toEqual(mockResults.length);
|
||||
});
|
||||
|
||||
it('returns only "video"-typed elements when the key value "video" is given', () => {
|
||||
const results = filteredResultsBySelection({ filterKey: 'video', results: mockResults });
|
||||
|
||||
expect(results.length).toEqual(2);
|
||||
});
|
||||
|
||||
it('returns only "course_outline"-typed elements when the key value "document" is given', () => {
|
||||
const results = filteredResultsBySelection({ filterKey: 'document', results: mockResults });
|
||||
|
||||
expect(results.length).toEqual(1);
|
||||
});
|
||||
|
||||
it('returns only "text"-typed elements when the key value "text" is given', () => {
|
||||
const results = filteredResultsBySelection({ filterKey: 'text', results: mockResults });
|
||||
|
||||
expect(results.length).toEqual(3);
|
||||
});
|
||||
});
|
||||
|
||||
describe('</CoursewareSearchResultsFilter />', () => {
|
||||
it('should render', async () => {
|
||||
await render(<CoursewareSearchResultsFilter results={mockResults} />);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.queryByTestId('courseware-search-results-tabs')).toBeInTheDocument();
|
||||
expect(screen.queryByText(/All content/)).toBeInTheDocument();
|
||||
expect(screen.queryByText(/Course outline/)).toBeInTheDocument();
|
||||
expect(screen.queryByText(/Text/)).toBeInTheDocument();
|
||||
expect(screen.queryByText(/Video/)).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
|
||||
it('should not render if no results are provided', async () => {
|
||||
await render(<CoursewareSearchResultsFilter results={[]} />);
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.queryByTestId('courseware-search-results-tabs')).not.toBeInTheDocument();
|
||||
expect(screen.queryByText(/All content/)).not.toBeInTheDocument();
|
||||
expect(screen.queryByText(/Course outline/)).not.toBeInTheDocument();
|
||||
expect(screen.queryByText(/Text/)).not.toBeInTheDocument();
|
||||
expect(screen.queryByText(/Video/)).not.toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
});
|
||||
});
|
||||
@@ -10,7 +10,7 @@ import { useElementBoundingBox, useLockScroll } from './hooks';
|
||||
import messages from './messages';
|
||||
|
||||
import CoursewareSearchForm from './CoursewareSearchForm';
|
||||
import CoursewareSearchResults from './CoursewareSearchResults';
|
||||
import CoursewareSearchResultsFilterContainer from './CoursewareResultsFilter';
|
||||
import mockedData from './test-data/mockedResults';
|
||||
|
||||
const CoursewareSearch = ({ intl, ...sectionProps }) => {
|
||||
@@ -50,9 +50,7 @@ const CoursewareSearch = ({ intl, ...sectionProps }) => {
|
||||
onSubmit={handleSubmit}
|
||||
placeholder={intl.formatMessage(messages.searchBarPlaceholderText)}
|
||||
/>
|
||||
{results !== undefined ? (
|
||||
<CoursewareSearchResults results={results} />
|
||||
) : null}
|
||||
<CoursewareSearchResultsFilterContainer results={results} />
|
||||
</div>
|
||||
</div>
|
||||
</section>
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
export default {
|
||||
results: PropTypes.arrayOf(PropTypes.objectOf({
|
||||
title: PropTypes.string.isRequired,
|
||||
href: PropTypes.string.isRequired,
|
||||
type: PropTypes.string,
|
||||
breadcrumbs: PropTypes.arrayOf(PropTypes.string),
|
||||
contentMatches: PropTypes.number,
|
||||
isExternal: PropTypes.bool,
|
||||
})),
|
||||
};
|
||||
Reference in New Issue
Block a user