feat: update filter naming on courseware search modal (#1255)
Update names to be one of the folow: 1. All Content 2. Text 3. Video 4. Section 5. Other
This commit is contained in:
@@ -1,4 +1,4 @@
|
||||
import React from 'react';
|
||||
import React, { useMemo } from 'react';
|
||||
import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
|
||||
import { Tabs, Tab } from '@edx/paragon';
|
||||
|
||||
@@ -8,12 +8,15 @@ import messages from './messages';
|
||||
import { useCoursewareSearchParams } from './hooks';
|
||||
import { useModel } from '../../generic/model-store';
|
||||
|
||||
const noFilterKey = 'none';
|
||||
const noFilterLabel = 'All content';
|
||||
|
||||
export const filteredResultsBySelection = ({ key = noFilterKey, results = [] }) => (
|
||||
key === noFilterKey ? results : results.filter(({ type }) => type === key)
|
||||
);
|
||||
const allFilterKey = 'all';
|
||||
const otherFilterKey = 'other';
|
||||
const allowedFilterKeys = {
|
||||
[allFilterKey]: true,
|
||||
text: true,
|
||||
video: true,
|
||||
sequence: true,
|
||||
[otherFilterKey]: true,
|
||||
};
|
||||
|
||||
export const CoursewareSearchResultsFilter = ({ intl }) => {
|
||||
const { courseId } = useParams();
|
||||
@@ -22,24 +25,25 @@ export const CoursewareSearchResultsFilter = ({ intl }) => {
|
||||
|
||||
if (!lastSearch || !lastSearch?.results?.length) { return null; }
|
||||
|
||||
const { total, results } = lastSearch;
|
||||
const { results: data = [] } = lastSearch;
|
||||
|
||||
const filters = [
|
||||
{
|
||||
key: noFilterKey,
|
||||
label: noFilterLabel,
|
||||
count: total,
|
||||
},
|
||||
...lastSearch.filters,
|
||||
];
|
||||
const results = useMemo(() => data.reduce((acc, { type, ...rest }) => {
|
||||
acc[allFilterKey] = [...(acc[allFilterKey] || []), { type: allFilterKey, ...rest }];
|
||||
if (type === allFilterKey) { return acc; }
|
||||
|
||||
const activeKey = filters.find(({ key }) => key === filterKeyword)?.key || noFilterKey;
|
||||
let targetKey = otherFilterKey;
|
||||
if (allowedFilterKeys[type]) { targetKey = type; }
|
||||
acc[targetKey] = [...(acc[targetKey] || []), { type: targetKey, ...rest }];
|
||||
return acc;
|
||||
}, {}), [data]);
|
||||
|
||||
const getFilterTitle = (key, fallback) => {
|
||||
const msg = messages[`filter:${key}`];
|
||||
if (!msg) { return fallback; }
|
||||
return intl.formatMessage(msg);
|
||||
};
|
||||
const filters = useMemo(() => Object.keys(allowedFilterKeys).map((key) => ({
|
||||
key,
|
||||
label: intl.formatMessage(messages[`filter:${key}`]),
|
||||
count: results[key].length,
|
||||
})), [results]);
|
||||
|
||||
const activeKey = allowedFilterKeys[filterKeyword] ? filterKeyword : allFilterKey;
|
||||
|
||||
return (
|
||||
<Tabs
|
||||
@@ -51,10 +55,8 @@ export const CoursewareSearchResultsFilter = ({ intl }) => {
|
||||
onSelect={setFilter}
|
||||
>
|
||||
{filters.map(({ key, label }) => (
|
||||
<Tab key={key} eventKey={key} title={getFilterTitle(key, label)}>
|
||||
<CoursewareSearchResults
|
||||
results={filteredResultsBySelection({ key, results })}
|
||||
/>
|
||||
<Tab key={key} eventKey={key} title={label} data-testid={`courseware-search-results-tabs-${key}`}>
|
||||
<CoursewareSearchResults results={results[key]} />
|
||||
</Tab>
|
||||
))}
|
||||
</Tabs>
|
||||
|
||||
@@ -8,7 +8,7 @@ import {
|
||||
screen,
|
||||
waitFor,
|
||||
} from '../../setupTest';
|
||||
import { CoursewareSearchResultsFilter, filteredResultsBySelection } from './CoursewareResultsFilter';
|
||||
import { CoursewareSearchResultsFilter } from './CoursewareResultsFilter';
|
||||
import { useCoursewareSearchParams } from './hooks';
|
||||
import initializeStore from '../../store';
|
||||
import { useModel } from '../../generic/model-store';
|
||||
@@ -19,27 +19,6 @@ jest.mock('../../generic/model-store', () => ({
|
||||
useModel: jest.fn(),
|
||||
}));
|
||||
|
||||
const mockResults = [
|
||||
{
|
||||
id: 'video-1', type: 'video', title: 'video_title', score: 3, contentHits: 1, url: '/video-1', location: ['path1', 'path2'],
|
||||
},
|
||||
{
|
||||
id: 'video-2', type: 'video', title: 'video_title2', score: 2, contentHits: 1, url: '/video-2', location: ['path1', 'path2'],
|
||||
},
|
||||
{
|
||||
id: 'document-1', type: 'document', title: 'document_title', score: 3, contentHits: 1, url: '/document-1', location: ['path1', 'path2'],
|
||||
},
|
||||
{
|
||||
id: 'text-1', type: 'text', title: 'text_title1', score: 3, contentHits: 1, url: '/text-1', location: ['path1', 'path2'],
|
||||
},
|
||||
{
|
||||
id: 'text-2', type: 'text', title: 'text_title2', score: 2, contentHits: 1, url: '/text-2', location: ['path1', 'path2'],
|
||||
},
|
||||
{
|
||||
id: 'text-3', type: 'text', title: 'text_title3', score: 1, contentHits: 1, url: '/text-3', location: ['path1', 'path2'],
|
||||
},
|
||||
];
|
||||
|
||||
const decodedCourseId = 'course-v1:edX+DemoX+Demo_Course';
|
||||
const decodedSequenceId = 'block-v1:edX+DemoX+Demo_Course+type@sequential+block@edx_introduction';
|
||||
const decodedUnitId = 'block-v1:edX+DemoX+Demo_Course+type@vertical+block@vertical_0270f6de40fc';
|
||||
@@ -73,38 +52,6 @@ function renderComponent(props = {}) {
|
||||
describe('CoursewareSearchResultsFilter', () => {
|
||||
beforeAll(initializeMockApp);
|
||||
|
||||
describe('filteredResultsBySelection', () => {
|
||||
it('returns a no values array when no results are provided', () => {
|
||||
const results = filteredResultsBySelection({});
|
||||
|
||||
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 only "video"-typed elements when the key value "video" is given', () => {
|
||||
const results = filteredResultsBySelection({ key: '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({ key: 'document', results: mockResults });
|
||||
|
||||
expect(results.length).toEqual(1);
|
||||
});
|
||||
|
||||
it('returns only "text"-typed elements when the key value "text" is given', () => {
|
||||
const results = filteredResultsBySelection({ key: 'text', results: mockResults });
|
||||
|
||||
expect(results.length).toEqual(3);
|
||||
});
|
||||
});
|
||||
|
||||
describe('</CoursewareSearchResultsFilter />', () => {
|
||||
beforeEach(() => {
|
||||
jest.clearAllMocks();
|
||||
@@ -117,8 +64,11 @@ describe('CoursewareSearchResultsFilter', () => {
|
||||
await renderComponent();
|
||||
|
||||
await waitFor(() => {
|
||||
expect(screen.queryByTestId('courseware-search-results-tabs')).toBeInTheDocument();
|
||||
expect(screen.queryByText(/All content/)).toBeInTheDocument();
|
||||
expect(screen.queryByTestId('courseware-search-results-tabs-all')).toBeInTheDocument();
|
||||
expect(screen.queryByTestId('courseware-search-results-tabs-text')).toBeInTheDocument();
|
||||
expect(screen.queryByTestId('courseware-search-results-tabs-video')).toBeInTheDocument();
|
||||
expect(screen.queryByTestId('courseware-search-results-tabs-sequence')).toBeInTheDocument();
|
||||
expect(screen.queryByTestId('courseware-search-results-tabs-other')).toBeInTheDocument();
|
||||
});
|
||||
});
|
||||
});
|
||||
|
||||
@@ -70,14 +70,13 @@ const CoursewareSearchResults = ({ results }) => {
|
||||
};
|
||||
|
||||
CoursewareSearchResults.propTypes = {
|
||||
results: PropTypes.arrayOf(PropTypes.objectOf({
|
||||
results: PropTypes.arrayOf(PropTypes.shape({
|
||||
id: PropTypes.string,
|
||||
title: PropTypes.string,
|
||||
type: PropTypes.string,
|
||||
location: PropTypes.arrayOf(PropTypes.string),
|
||||
url: PropTypes.string,
|
||||
contentHits: PropTypes.number,
|
||||
score: PropTypes.number,
|
||||
})),
|
||||
};
|
||||
|
||||
|
||||
@@ -53,8 +53,8 @@ const messages = defineMessages({
|
||||
},
|
||||
|
||||
// These are translations for labeling the filters
|
||||
'filter:none': {
|
||||
id: 'learn.coursewareSerch.filter:none',
|
||||
'filter:all': {
|
||||
id: 'learn.coursewareSerch.filter:all',
|
||||
defaultMessage: 'All content',
|
||||
description: 'Label for the search results filter that shows all content (no filter).',
|
||||
},
|
||||
@@ -68,6 +68,16 @@ const messages = defineMessages({
|
||||
defaultMessage: 'Video',
|
||||
description: 'Label for the search results filter that shows results with video content.',
|
||||
},
|
||||
'filter:sequence': {
|
||||
id: 'learn.coursewareSerch.filter:sequence',
|
||||
defaultMessage: 'Section',
|
||||
description: 'Label for the search results filter that shows results with section content.',
|
||||
},
|
||||
'filter:other': {
|
||||
id: 'learn.coursewareSerch.filter:other',
|
||||
defaultMessage: 'Other',
|
||||
description: 'Label for the search results filter that shows results with other content.',
|
||||
},
|
||||
});
|
||||
|
||||
export default messages;
|
||||
|
||||
Reference in New Issue
Block a user