diff --git a/package-lock.json b/package-lock.json
index 91de9b9..31a8501 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -20,7 +20,7 @@
"@fortawesome/free-brands-svg-icons": "^5.15.4",
"@fortawesome/free-solid-svg-icons": "^5.15.4",
"@fortawesome/react-fontawesome": "^0.1.15",
- "@openedx/frontend-plugin-framework": "1.0.2",
+ "@openedx/frontend-plugin-framework": "^1.0.2",
"@openedx/paragon": "^21.11.3",
"@optimizely/react-sdk": "^2.9.2",
"@redux-beacon/segment": "^1.1.0",
diff --git a/package.json b/package.json
index 6705b2f..6b85510 100755
--- a/package.json
+++ b/package.json
@@ -33,11 +33,11 @@
"@edx/frontend-platform": "7.1.0",
"@edx/openedx-atlas": "^0.6.0",
"@edx/react-unit-test-utils": "2.0.0",
- "@openedx/frontend-plugin-framework": "1.0.2",
"@fortawesome/fontawesome-svg-core": "^1.2.36",
"@fortawesome/free-brands-svg-icons": "^5.15.4",
"@fortawesome/free-solid-svg-icons": "^5.15.4",
"@fortawesome/react-fontawesome": "^0.1.15",
+ "@openedx/frontend-plugin-framework": "^1.0.2",
"@openedx/paragon": "^21.11.3",
"@optimizely/react-sdk": "^2.9.2",
"@redux-beacon/segment": "^1.1.0",
diff --git a/src/containers/CourseList/__snapshots__/index.test.jsx.snap b/src/containers/CourseList/__snapshots__/index.test.jsx.snap
deleted file mode 100644
index fe6523e..0000000
--- a/src/containers/CourseList/__snapshots__/index.test.jsx.snap
+++ /dev/null
@@ -1,185 +0,0 @@
-// Jest Snapshot v1, https://goo.gl/fbAQLP
-
-exports[`CourseList collapsed with multiple courses and pages snapshot 1`] = `
-
-`;
-
-exports[`CourseList no courses snapshot 1`] = `
-
-`;
-
-exports[`CourseList no filters snapshot 1`] = `
-
-`;
-
-exports[`CourseList with filters snapshot 1`] = `
-
-`;
-
-exports[`CourseList with multiple courses and pages snapshot 1`] = `
-
-`;
diff --git a/src/containers/CourseList/index.jsx b/src/containers/CourseList/index.jsx
deleted file mode 100644
index 6ca9819..0000000
--- a/src/containers/CourseList/index.jsx
+++ /dev/null
@@ -1,77 +0,0 @@
-import React from 'react';
-
-import { useIntl } from '@edx/frontend-platform/i18n';
-import { Pagination } from '@openedx/paragon';
-
-import { reduxHooks } from 'hooks';
-import {
- ActiveCourseFilters,
- CourseFilterControls,
-} from 'containers/CourseFilterControls';
-import CourseCard from 'containers/CourseCard';
-import NoCoursesView from './NoCoursesView';
-
-import { useCourseListData, useIsCollapsed } from './hooks';
-
-import messages from './messages';
-
-import './index.scss';
-
-/**
- * Renders the list of CourseCards, as well as the controls (CourseFilterControls) for modifying the list.
- * Also houses the NoCoursesView to display if the user hasn't enrolled in any courses.
- * @returns List of courses as CourseCards
- */
-export const CourseList = () => {
- const { formatMessage } = useIntl();
- const hasCourses = reduxHooks.useHasCourses();
- const {
- filterOptions,
- setPageNumber,
- numPages,
- showFilters,
- visibleList,
- } = useCourseListData();
- const isCollapsed = useIsCollapsed();
-
- return (
-
-
-
{formatMessage(messages.myCourses)}
-
-
-
-
- {hasCourses
- ? (
- <>
- {showFilters && (
-
- )}
-
- {visibleList.map(({ cardId }) => (
-
- ))}
- {numPages > 1 && (
-
- )}
-
- >
- ) : (
-
- )}
-
- );
-};
-
-CourseList.propTypes = {};
-
-export default CourseList;
diff --git a/src/containers/CoursesPanel/CourseList/__snapshots__/index.test.jsx.snap b/src/containers/CoursesPanel/CourseList/__snapshots__/index.test.jsx.snap
new file mode 100644
index 0000000..8988932
--- /dev/null
+++ b/src/containers/CoursesPanel/CourseList/__snapshots__/index.test.jsx.snap
@@ -0,0 +1,70 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`CourseList collapsed with multiple courses and pages snapshot 1`] = `
+
+
+
+
+`;
+
+exports[`CourseList no courses or filters snapshot 1`] = `
+
+
+
+`;
+
+exports[`CourseList with filters snapshot 1`] = `undefined`;
+
+exports[`CourseList with multiple courses and pages snapshot 1`] = `
+
+
+
+`;
diff --git a/src/containers/CoursesPanel/CourseList/hooks.js b/src/containers/CoursesPanel/CourseList/hooks.js
new file mode 100644
index 0000000..9cff96c
--- /dev/null
+++ b/src/containers/CoursesPanel/CourseList/hooks.js
@@ -0,0 +1,8 @@
+import { useWindowSize, breakpoints } from '@openedx/paragon';
+
+export const useIsCollapsed = () => {
+ const { width } = useWindowSize();
+ return width < breakpoints.medium.maxWidth;
+};
+
+export default useIsCollapsed;
diff --git a/src/containers/CoursesPanel/CourseList/index.jsx b/src/containers/CoursesPanel/CourseList/index.jsx
new file mode 100644
index 0000000..2f6111a
--- /dev/null
+++ b/src/containers/CoursesPanel/CourseList/index.jsx
@@ -0,0 +1,51 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+
+import { Pagination } from '@openedx/paragon';
+import {
+ ActiveCourseFilters,
+} from 'containers/CourseFilterControls';
+import CourseCard from 'containers/CourseCard';
+
+import { useIsCollapsed } from './hooks';
+
+export const CourseList = ({
+ filterOptions, setPageNumber, numPages, showFilters, visibleList,
+}) => {
+ const isCollapsed = useIsCollapsed();
+ return (
+ <>
+ {showFilters && (
+
+ )}
+
+ {visibleList.map(({ cardId }) => (
+
+ ))}
+ {numPages > 1 && (
+
+ )}
+
+ >
+ );
+};
+
+CourseList.propTypes = {
+ showFilters: PropTypes.bool.isRequired,
+ // eslint-disable-next-line react/forbid-prop-types
+ visibleList: PropTypes.arrayOf(PropTypes.object).isRequired,
+ // eslint-disable-next-line react/forbid-prop-types
+ filterOptions: PropTypes.object.isRequired,
+ numPages: PropTypes.number.isRequired,
+ setPageNumber: PropTypes.func.isRequired,
+};
+
+export default CourseList;
diff --git a/src/containers/CourseList/index.test.jsx b/src/containers/CoursesPanel/CourseList/index.test.jsx
similarity index 68%
rename from src/containers/CourseList/index.test.jsx
rename to src/containers/CoursesPanel/CourseList/index.test.jsx
index 8621722..a2e09b3 100644
--- a/src/containers/CourseList/index.test.jsx
+++ b/src/containers/CoursesPanel/CourseList/index.test.jsx
@@ -1,26 +1,17 @@
import { shallow } from '@edx/react-unit-test-utils';
-import { reduxHooks } from 'hooks';
-import { useCourseListData, useIsCollapsed } from './hooks';
+import { useIsCollapsed } from './hooks';
import CourseList from '.';
-jest.mock('hooks', () => ({
- reduxHooks: { useHasCourses: jest.fn() },
-}));
-
jest.mock('./hooks', () => ({
- useCourseListData: jest.fn(),
useIsCollapsed: jest.fn(),
}));
jest.mock('containers/CourseCard', () => 'CourseCard');
jest.mock('containers/CourseFilterControls', () => ({
ActiveCourseFilters: 'ActiveCourseFilters',
- CourseFilterControls: 'CourseFilterControls',
}));
-reduxHooks.useHasCourses.mockReturnValue(true);
-
describe('CourseList', () => {
const defaultCourseListData = {
filterOptions: {},
@@ -30,22 +21,12 @@ describe('CourseList', () => {
visibleList: [],
};
useIsCollapsed.mockReturnValue(false);
- const createWrapper = (courseListData) => {
- useCourseListData.mockReturnValueOnce({
- ...defaultCourseListData,
- ...courseListData,
- });
- return shallow();
- };
- describe('no courses', () => {
- test('snapshot', () => {
- reduxHooks.useHasCourses.mockReturnValue(true);
- const wrapper = createWrapper();
- expect(wrapper.snapshot).toMatchSnapshot();
- });
- });
- describe('no filters', () => {
+ const createWrapper = (courseListData = defaultCourseListData) => (
+ shallow()
+ );
+
+ describe('no courses or filters', () => {
test('snapshot', () => {
const wrapper = createWrapper();
expect(wrapper.snapshot).toMatchSnapshot();
diff --git a/src/containers/CourseList/NoCoursesView/__snapshots__/index.test.jsx.snap b/src/containers/CoursesPanel/NoCoursesView/__snapshots__/index.test.jsx.snap
similarity index 100%
rename from src/containers/CourseList/NoCoursesView/__snapshots__/index.test.jsx.snap
rename to src/containers/CoursesPanel/NoCoursesView/__snapshots__/index.test.jsx.snap
diff --git a/src/containers/CourseList/NoCoursesView/index.jsx b/src/containers/CoursesPanel/NoCoursesView/index.jsx
similarity index 100%
rename from src/containers/CourseList/NoCoursesView/index.jsx
rename to src/containers/CoursesPanel/NoCoursesView/index.jsx
diff --git a/src/containers/CourseList/NoCoursesView/index.scss b/src/containers/CoursesPanel/NoCoursesView/index.scss
similarity index 100%
rename from src/containers/CourseList/NoCoursesView/index.scss
rename to src/containers/CoursesPanel/NoCoursesView/index.scss
diff --git a/src/containers/CourseList/NoCoursesView/index.test.jsx b/src/containers/CoursesPanel/NoCoursesView/index.test.jsx
similarity index 100%
rename from src/containers/CourseList/NoCoursesView/index.test.jsx
rename to src/containers/CoursesPanel/NoCoursesView/index.test.jsx
diff --git a/src/containers/CourseList/NoCoursesView/messages.js b/src/containers/CoursesPanel/NoCoursesView/messages.js
similarity index 100%
rename from src/containers/CourseList/NoCoursesView/messages.js
rename to src/containers/CoursesPanel/NoCoursesView/messages.js
diff --git a/src/containers/CoursesPanel/__snapshots__/index.test.jsx.snap b/src/containers/CoursesPanel/__snapshots__/index.test.jsx.snap
new file mode 100644
index 0000000..4ac541b
--- /dev/null
+++ b/src/containers/CoursesPanel/__snapshots__/index.test.jsx.snap
@@ -0,0 +1,51 @@
+// Jest Snapshot v1, https://goo.gl/fbAQLP
+
+exports[`CoursesPanel no courses snapshot 1`] = `
+
+`;
+
+exports[`CoursesPanel with courses snapshot 1`] = `
+
+`;
diff --git a/src/containers/CourseList/hooks.js b/src/containers/CoursesPanel/hooks.js
similarity index 82%
rename from src/containers/CourseList/hooks.js
rename to src/containers/CoursesPanel/hooks.js
index f585b22..dcc5a60 100644
--- a/src/containers/CourseList/hooks.js
+++ b/src/containers/CoursesPanel/hooks.js
@@ -1,6 +1,5 @@
import React from 'react';
-import { useWindowSize, breakpoints } from '@openedx/paragon';
import queryString from 'query-string';
import { ListPageSize, SortKeys } from 'data/constants/app';
@@ -9,21 +8,16 @@ import { StrictDict } from 'utils';
import * as module from './hooks';
-export const useIsCollapsed = () => {
- const { width } = useWindowSize();
- return width < breakpoints.medium.maxWidth;
-};
-
export const state = StrictDict({
sortBy: (val) => React.useState(val), // eslint-disable-line
});
/**
* Filters are fetched from the store and used to generate a list of "visible" courses.
- * Other values returned and used for the layout of the CourseList component are:
+ * Other values returned and used for the layout of the CoursesPanel component are:
* the current page number, the sorting method, and whether or not to enable filters and pagination.
*
- * @returns data for the CourseList component
+ * @returns data for the CoursesPanel component
*/
export const useCourseListData = () => {
const filters = reduxHooks.useFilters();
diff --git a/src/containers/CourseList/hooks.test.js b/src/containers/CoursesPanel/hooks.test.js
similarity index 100%
rename from src/containers/CourseList/hooks.test.js
rename to src/containers/CoursesPanel/hooks.test.js
diff --git a/src/containers/CoursesPanel/index.jsx b/src/containers/CoursesPanel/index.jsx
new file mode 100644
index 0000000..8fd1e56
--- /dev/null
+++ b/src/containers/CoursesPanel/index.jsx
@@ -0,0 +1,48 @@
+import React from 'react';
+
+import { useIntl } from '@edx/frontend-platform/i18n';
+
+import { reduxHooks } from 'hooks';
+import {
+ CourseFilterControls,
+} from 'containers/CourseFilterControls';
+import NoCoursesView from './NoCoursesView';
+
+import CourseList from './CourseList';
+
+import { useCourseListData } from './hooks';
+
+import messages from './messages';
+
+import './index.scss';
+
+/**
+ * Renders the list of CourseCards, as well as the controls (CourseFilterControls) for modifying the list.
+ * Also houses the NoCoursesView to display if the user hasn't enrolled in any courses.
+ * @returns List of courses as CourseCards or empty state
+*/
+export const CoursesPanel = () => {
+ const { formatMessage } = useIntl();
+ const hasCourses = reduxHooks.useHasCourses();
+ const courseListData = useCourseListData();
+ return (
+
+
+
{formatMessage(messages.myCourses)}
+
+
+
+
+ {hasCourses
+ ? (
+
+ ) : (
+
+ )}
+
+ );
+};
+
+CoursesPanel.propTypes = {};
+
+export default CoursesPanel;
diff --git a/src/containers/CourseList/index.scss b/src/containers/CoursesPanel/index.scss
similarity index 100%
rename from src/containers/CourseList/index.scss
rename to src/containers/CoursesPanel/index.scss
diff --git a/src/containers/CoursesPanel/index.test.jsx b/src/containers/CoursesPanel/index.test.jsx
new file mode 100644
index 0000000..72aedb3
--- /dev/null
+++ b/src/containers/CoursesPanel/index.test.jsx
@@ -0,0 +1,55 @@
+import { shallow } from '@edx/react-unit-test-utils';
+
+import { reduxHooks } from 'hooks';
+import { useCourseListData } from './hooks';
+import CoursesPanel from '.';
+
+jest.mock('hooks', () => ({
+ reduxHooks: { useHasCourses: jest.fn() },
+}));
+
+jest.mock('./hooks', () => ({
+ useCourseListData: jest.fn(),
+}));
+
+jest.mock('containers/CourseCard', () => 'CourseCard');
+jest.mock('containers/CourseFilterControls', () => ({
+ ActiveCourseFilters: 'ActiveCourseFilters',
+ CourseFilterControls: 'CourseFilterControls',
+}));
+jest.mock('./CourseList', () => 'CourseList');
+
+reduxHooks.useHasCourses.mockReturnValue(true);
+
+describe('CoursesPanel', () => {
+ const defaultCourseListData = {
+ filterOptions: {},
+ numPages: 1,
+ setPageNumber: jest.fn().mockName('setPageNumber'),
+ showFilters: false,
+ visibleList: [],
+ };
+
+ const createWrapper = (courseListData) => {
+ useCourseListData.mockReturnValueOnce({
+ ...defaultCourseListData,
+ ...courseListData,
+ });
+ return shallow();
+ };
+
+ describe('no courses', () => {
+ test('snapshot', () => {
+ reduxHooks.useHasCourses.mockReturnValue(false);
+ const wrapper = createWrapper();
+ expect(wrapper.snapshot).toMatchSnapshot();
+ });
+ });
+ describe('with courses', () => {
+ test('snapshot', () => {
+ reduxHooks.useHasCourses.mockReturnValue(true);
+ const wrapper = createWrapper();
+ expect(wrapper.snapshot).toMatchSnapshot();
+ });
+ });
+});
diff --git a/src/containers/CourseList/messages.js b/src/containers/CoursesPanel/messages.js
similarity index 100%
rename from src/containers/CourseList/messages.js
rename to src/containers/CoursesPanel/messages.js
diff --git a/src/containers/Dashboard/__snapshots__/index.test.jsx.snap b/src/containers/Dashboard/__snapshots__/index.test.jsx.snap
index 593d90f..67abc57 100644
--- a/src/containers/Dashboard/__snapshots__/index.test.jsx.snap
+++ b/src/containers/Dashboard/__snapshots__/index.test.jsx.snap
@@ -20,7 +20,7 @@ exports[`Dashboard snapshots courses loaded, show select session modal, no avail
-
+
@@ -65,7 +65,7 @@ exports[`Dashboard snapshots there are no courses, there ARE available dashboard
-
+
diff --git a/src/containers/Dashboard/index.jsx b/src/containers/Dashboard/index.jsx
index c0c76cc..c6c065b 100644
--- a/src/containers/Dashboard/index.jsx
+++ b/src/containers/Dashboard/index.jsx
@@ -4,7 +4,7 @@ import { reduxHooks } from 'hooks';
import { RequestKeys } from 'data/constants/requests';
import EnterpriseDashboardModal from 'containers/EnterpriseDashboardModal';
import SelectSessionModal from 'containers/SelectSessionModal';
-import CourseList from 'containers/CourseList';
+import CoursesPanel from 'containers/CoursesPanel';
import LoadedSidebar from 'containers/WidgetContainers/LoadedSidebar';
import NoCoursesSidebar from 'containers/WidgetContainers/NoCoursesSidebar';
@@ -36,7 +36,7 @@ export const Dashboard = () => {
? ()
: (
-
+
)}
diff --git a/src/containers/Dashboard/index.test.jsx b/src/containers/Dashboard/index.test.jsx
index c802205..ffac108 100644
--- a/src/containers/Dashboard/index.test.jsx
+++ b/src/containers/Dashboard/index.test.jsx
@@ -4,7 +4,7 @@ import { reduxHooks } from 'hooks';
import EnterpriseDashboardModal from 'containers/EnterpriseDashboardModal';
import SelectSessionModal from 'containers/SelectSessionModal';
-import CourseList from 'containers/CourseList';
+import CoursesPanel from 'containers/CoursesPanel';
import LoadedWidgetSidebar from 'containers/WidgetContainers/LoadedSidebar';
import NoCoursesWidgetSidebar from 'containers/WidgetContainers/NoCoursesSidebar';
@@ -24,7 +24,7 @@ jest.mock('hooks', () => ({
}));
jest.mock('containers/EnterpriseDashboardModal', () => 'EnterpriseDashboardModal');
-jest.mock('containers/CourseList', () => 'CourseList');
+jest.mock('containers/CoursesPanel', () => 'CoursesPanel');
jest.mock('containers/WidgetContainers/LoadedSidebar', () => 'LoadedWidgetSidebar');
jest.mock('containers/WidgetContainers/NoCoursesSidebar', () => 'NoCoursesWidgetSidebar');
jest.mock('./LoadingView', () => 'LoadingView');
@@ -116,7 +116,7 @@ describe('Dashboard', () => {
showSelectSessionModal: true,
},
content: ['LoadedView', (
-
+
)],
showEnterpriseModal: false,
showSelectSessionModal: true,
@@ -132,7 +132,7 @@ describe('Dashboard', () => {
showSelectSessionModal: false,
},
content: ['Dashboard layout with no courses sidebar and content', (
-
+
)],
showEnterpriseModal: true,
showSelectSessionModal: false,
diff --git a/src/data/redux/app/selectors/simpleSelectors.test.js b/src/data/redux/app/selectors/simpleSelectors.test.js
index 353c528..02dad82 100644
--- a/src/data/redux/app/selectors/simpleSelectors.test.js
+++ b/src/data/redux/app/selectors/simpleSelectors.test.js
@@ -29,6 +29,7 @@ describe('app simple selectors', () => {
keys.selectSessionModal,
keys.pageNumber,
keys.socialShareSettings,
+ keys.filters,
])('%s app simple selector forwards corresponding data from app store', (key) => {
testState = { app: { [key]: testString, otherField: 'fake string' } };
const { preSelectors, cb } = simpleSelectors[key];
diff --git a/src/widgets/ProductRecommendations/index.jsx b/src/widgets/ProductRecommendations/index.jsx
index f3eb316..2b61877 100644
--- a/src/widgets/ProductRecommendations/index.jsx
+++ b/src/widgets/ProductRecommendations/index.jsx
@@ -1,7 +1,7 @@
import React from 'react';
import './index.scss';
import { reduxHooks } from 'hooks';
-import NoCoursesView from 'containers/CourseList/NoCoursesView';
+import NoCoursesView from 'containers/CoursesPanel/NoCoursesView';
import LoadingView from './components/LoadingView';
import LoadedView from './components/LoadedView';
import hooks from './hooks';
diff --git a/src/widgets/ProductRecommendations/index.test.jsx b/src/widgets/ProductRecommendations/index.test.jsx
index ab343b9..8ab3a4e 100644
--- a/src/widgets/ProductRecommendations/index.test.jsx
+++ b/src/widgets/ProductRecommendations/index.test.jsx
@@ -5,7 +5,7 @@ import hooks from './hooks';
import ProductRecommendations from './index';
import LoadingView from './components/LoadingView';
import LoadedView from './components/LoadedView';
-import NoCoursesView from '../../containers/CourseList/NoCoursesView';
+import NoCoursesView from '../../containers/CoursesPanel/NoCoursesView';
import { mockCrossProductResponse, mockAmplitudeResponse } from './testData';
jest.mock('./hooks', () => ({
@@ -21,7 +21,7 @@ jest.mock('hooks', () => ({
jest.mock('./components/LoadingView', () => 'LoadingView');
jest.mock('./components/LoadedView', () => 'LoadedView');
-jest.mock('containers/CourseList/NoCoursesView', () => 'NoCoursesView');
+jest.mock('containers/CoursesPanel/NoCoursesView', () => 'NoCoursesView');
describe('ProductRecommendations', () => {
const defaultValues = {