Skip to content

Commit b3a06fd

Browse files
feat: update filter naming on courseware search modal (openedx#1255)
Update names to be one of the folow: 1. All Content 2. Text 3. Video 4. Section 5. Other
1 parent 684ac49 commit b3a06fd

File tree

4 files changed

+47
-86
lines changed

4 files changed

+47
-86
lines changed

src/course-home/courseware-search/CoursewareResultsFilter.jsx

Lines changed: 28 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
import React from 'react';
1+
import React, { useMemo } from 'react';
22
import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
33
import { Tabs, Tab } from '@edx/paragon';
44

@@ -8,12 +8,15 @@ import messages from './messages';
88
import { useCoursewareSearchParams } from './hooks';
99
import { useModel } from '../../generic/model-store';
1010

11-
const noFilterKey = 'none';
12-
const noFilterLabel = 'All content';
13-
14-
export const filteredResultsBySelection = ({ key = noFilterKey, results = [] }) => (
15-
key === noFilterKey ? results : results.filter(({ type }) => type === key)
16-
);
11+
const allFilterKey = 'all';
12+
const otherFilterKey = 'other';
13+
const allowedFilterKeys = {
14+
[allFilterKey]: true,
15+
text: true,
16+
video: true,
17+
sequence: true,
18+
[otherFilterKey]: true,
19+
};
1720

1821
export const CoursewareSearchResultsFilter = ({ intl }) => {
1922
const { courseId } = useParams();
@@ -22,24 +25,25 @@ export const CoursewareSearchResultsFilter = ({ intl }) => {
2225

2326
if (!lastSearch || !lastSearch?.results?.length) { return null; }
2427

25-
const { total, results } = lastSearch;
28+
const { results: data = [] } = lastSearch;
29+
30+
const results = useMemo(() => data.reduce((acc, { type, ...rest }) => {
31+
acc[allFilterKey] = [...(acc[allFilterKey] || []), { type: allFilterKey, ...rest }];
32+
if (type === allFilterKey) { return acc; }
2633

27-
const filters = [
28-
{
29-
key: noFilterKey,
30-
label: noFilterLabel,
31-
count: total,
32-
},
33-
...lastSearch.filters,
34-
];
34+
let targetKey = otherFilterKey;
35+
if (allowedFilterKeys[type]) { targetKey = type; }
36+
acc[targetKey] = [...(acc[targetKey] || []), { type: targetKey, ...rest }];
37+
return acc;
38+
}, {}), [data]);
3539

36-
const activeKey = filters.find(({ key }) => key === filterKeyword)?.key || noFilterKey;
40+
const filters = useMemo(() => Object.keys(allowedFilterKeys).map((key) => ({
41+
key,
42+
label: intl.formatMessage(messages[`filter:${key}`]),
43+
count: results[key].length,
44+
})), [results]);
3745

38-
const getFilterTitle = (key, fallback) => {
39-
const msg = messages[`filter:${key}`];
40-
if (!msg) { return fallback; }
41-
return intl.formatMessage(msg);
42-
};
46+
const activeKey = allowedFilterKeys[filterKeyword] ? filterKeyword : allFilterKey;
4347

4448
return (
4549
<Tabs
@@ -51,10 +55,8 @@ export const CoursewareSearchResultsFilter = ({ intl }) => {
5155
onSelect={setFilter}
5256
>
5357
{filters.map(({ key, label }) => (
54-
<Tab key={key} eventKey={key} title={getFilterTitle(key, label)}>
55-
<CoursewareSearchResults
56-
results={filteredResultsBySelection({ key, results })}
57-
/>
58+
<Tab key={key} eventKey={key} title={label} data-testid={`courseware-search-results-tabs-${key}`}>
59+
<CoursewareSearchResults results={results[key]} />
5860
</Tab>
5961
))}
6062
</Tabs>

src/course-home/courseware-search/CoursewareResultsFilter.test.jsx

Lines changed: 6 additions & 56 deletions
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ import {
88
screen,
99
waitFor,
1010
} from '../../setupTest';
11-
import { CoursewareSearchResultsFilter, filteredResultsBySelection } from './CoursewareResultsFilter';
11+
import { CoursewareSearchResultsFilter } from './CoursewareResultsFilter';
1212
import { useCoursewareSearchParams } from './hooks';
1313
import initializeStore from '../../store';
1414
import { useModel } from '../../generic/model-store';
@@ -19,27 +19,6 @@ jest.mock('../../generic/model-store', () => ({
1919
useModel: jest.fn(),
2020
}));
2121

22-
const mockResults = [
23-
{
24-
id: 'video-1', type: 'video', title: 'video_title', score: 3, contentHits: 1, url: '/video-1', location: ['path1', 'path2'],
25-
},
26-
{
27-
id: 'video-2', type: 'video', title: 'video_title2', score: 2, contentHits: 1, url: '/video-2', location: ['path1', 'path2'],
28-
},
29-
{
30-
id: 'document-1', type: 'document', title: 'document_title', score: 3, contentHits: 1, url: '/document-1', location: ['path1', 'path2'],
31-
},
32-
{
33-
id: 'text-1', type: 'text', title: 'text_title1', score: 3, contentHits: 1, url: '/text-1', location: ['path1', 'path2'],
34-
},
35-
{
36-
id: 'text-2', type: 'text', title: 'text_title2', score: 2, contentHits: 1, url: '/text-2', location: ['path1', 'path2'],
37-
},
38-
{
39-
id: 'text-3', type: 'text', title: 'text_title3', score: 1, contentHits: 1, url: '/text-3', location: ['path1', 'path2'],
40-
},
41-
];
42-
4322
const decodedCourseId = 'course-v1:edX+DemoX+Demo_Course';
4423
const decodedSequenceId = 'block-v1:edX+DemoX+Demo_Course+type@sequential+block@edx_introduction';
4524
const decodedUnitId = 'block-v1:edX+DemoX+Demo_Course+type@vertical+block@vertical_0270f6de40fc';
@@ -73,38 +52,6 @@ function renderComponent(props = {}) {
7352
describe('CoursewareSearchResultsFilter', () => {
7453
beforeAll(initializeMockApp);
7554

76-
describe('filteredResultsBySelection', () => {
77-
it('returns a no values array when no results are provided', () => {
78-
const results = filteredResultsBySelection({});
79-
80-
expect(results.length).toEqual(0);
81-
});
82-
83-
it('returns all values when no key value is provided', () => {
84-
const results = filteredResultsBySelection({ results: mockResults });
85-
86-
expect(results.length).toEqual(mockResults.length);
87-
});
88-
89-
it('returns only "video"-typed elements when the key value "video" is given', () => {
90-
const results = filteredResultsBySelection({ key: 'video', results: mockResults });
91-
92-
expect(results.length).toEqual(2);
93-
});
94-
95-
it('returns only "course_outline"-typed elements when the key value "document" is given', () => {
96-
const results = filteredResultsBySelection({ key: 'document', results: mockResults });
97-
98-
expect(results.length).toEqual(1);
99-
});
100-
101-
it('returns only "text"-typed elements when the key value "text" is given', () => {
102-
const results = filteredResultsBySelection({ key: 'text', results: mockResults });
103-
104-
expect(results.length).toEqual(3);
105-
});
106-
});
107-
10855
describe('</CoursewareSearchResultsFilter />', () => {
10956
beforeEach(() => {
11057
jest.clearAllMocks();
@@ -117,8 +64,11 @@ describe('CoursewareSearchResultsFilter', () => {
11764
await renderComponent();
11865

11966
await waitFor(() => {
120-
expect(screen.queryByTestId('courseware-search-results-tabs')).toBeInTheDocument();
121-
expect(screen.queryByText(/All content/)).toBeInTheDocument();
67+
expect(screen.queryByTestId('courseware-search-results-tabs-all')).toBeInTheDocument();
68+
expect(screen.queryByTestId('courseware-search-results-tabs-text')).toBeInTheDocument();
69+
expect(screen.queryByTestId('courseware-search-results-tabs-video')).toBeInTheDocument();
70+
expect(screen.queryByTestId('courseware-search-results-tabs-sequence')).toBeInTheDocument();
71+
expect(screen.queryByTestId('courseware-search-results-tabs-other')).toBeInTheDocument();
12272
});
12373
});
12474
});

src/course-home/courseware-search/CoursewareSearchResults.jsx

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -70,14 +70,13 @@ const CoursewareSearchResults = ({ results }) => {
7070
};
7171

7272
CoursewareSearchResults.propTypes = {
73-
results: PropTypes.arrayOf(PropTypes.objectOf({
73+
results: PropTypes.arrayOf(PropTypes.shape({
7474
id: PropTypes.string,
7575
title: PropTypes.string,
7676
type: PropTypes.string,
7777
location: PropTypes.arrayOf(PropTypes.string),
7878
url: PropTypes.string,
7979
contentHits: PropTypes.number,
80-
score: PropTypes.number,
8180
})),
8281
};
8382

src/course-home/courseware-search/messages.js

Lines changed: 12 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,8 @@ const messages = defineMessages({
5353
},
5454

5555
// These are translations for labeling the filters
56-
'filter:none': {
57-
id: 'learn.coursewareSerch.filter:none',
56+
'filter:all': {
57+
id: 'learn.coursewareSerch.filter:all',
5858
defaultMessage: 'All content',
5959
description: 'Label for the search results filter that shows all content (no filter).',
6060
},
@@ -68,6 +68,16 @@ const messages = defineMessages({
6868
defaultMessage: 'Video',
6969
description: 'Label for the search results filter that shows results with video content.',
7070
},
71+
'filter:sequence': {
72+
id: 'learn.coursewareSerch.filter:sequence',
73+
defaultMessage: 'Section',
74+
description: 'Label for the search results filter that shows results with section content.',
75+
},
76+
'filter:other': {
77+
id: 'learn.coursewareSerch.filter:other',
78+
defaultMessage: 'Other',
79+
description: 'Label for the search results filter that shows results with other content.',
80+
},
7181
});
7282

7383
export default messages;

0 commit comments

Comments
 (0)