+
@@ -82,7 +101,11 @@ export default function DiscussionsHome() {
-
+
{
postEditorVisible ? (
@@ -102,6 +125,7 @@ export default function DiscussionsHome() {
+ {!inContext &&
}
);
}
diff --git a/src/discussions/discussions-home/DiscussionsHome.test.jsx b/src/discussions/discussions-home/DiscussionsHome.test.jsx
index 5f778852..aaa153c1 100644
--- a/src/discussions/discussions-home/DiscussionsHome.test.jsx
+++ b/src/discussions/discussions-home/DiscussionsHome.test.jsx
@@ -1,27 +1,28 @@
-import {
- fireEvent, render, screen,
-} from '@testing-library/react';
+import { fireEvent, render, screen } from '@testing-library/react';
import { IntlProvider } from 'react-intl';
+import { Context as ResponsiveContext } from 'react-responsive';
import { MemoryRouter } from 'react-router';
import { initializeMockApp } from '@edx/frontend-platform';
import { AppProvider } from '@edx/frontend-platform/react';
-import { Routes } from '../../data/constants';
import { initializeStore } from '../../store';
import navigationBarMessages from '../navigation/navigation-bar/messages';
import DiscussionsHome from './DiscussionsHome';
let store;
+const courseId = 'course-v1:edX+DemoX+Demo_Course';
-function renderComponent() {
+function renderComponent(location = `/discussions/${courseId}/`) {
render(
-
-
-
-
-
+
+
+
+
+
+
+
,
);
}
@@ -40,7 +41,7 @@ describe('DiscussionsHome', () => {
store = initializeStore();
});
- it('clicking "All Topics" button renders topics view', async () => {
+ test('clicking "All Topics" button renders topics view', async () => {
renderComponent();
const allTopicsButton = await screen.findByText(navigationBarMessages.allTopics.defaultMessage);
@@ -48,4 +49,41 @@ describe('DiscussionsHome', () => {
await screen.findByTestId('topics-view');
});
+
+ test('full view should show header and footer and hide close button', async () => {
+ renderComponent(`/discussions/${courseId}/topics`);
+ expect(screen.queryByText(navigationBarMessages.allTopics.defaultMessage))
+ .toBeInTheDocument();
+ expect(screen.queryByRole('button', { name: 'Close' }))
+ .not
+ .toBeInTheDocument();
+ // Header should be visible
+ expect(screen.queryByRole('button', {
+ name: /account menu for abc123/i,
+ }))
+ .toBeInTheDocument();
+ // Footer should be visible
+ expect(screen.queryByRole('contentinfo'))
+ .toBeInTheDocument();
+ });
+
+ test('in-context view should hide header and footer and show close button', async () => {
+ renderComponent(`/discussions/${courseId}/topics?inContext`);
+
+ expect(screen.queryByText(navigationBarMessages.allTopics.defaultMessage))
+ .not
+ .toBeInTheDocument();
+ expect(screen.queryByRole('button', { name: 'Close' }))
+ .toBeInTheDocument();
+ // Header should be hidden
+ expect(screen.queryByRole('button', {
+ name: /account menu for abc123/i,
+ }))
+ .not
+ .toBeInTheDocument();
+ // Footer should be hidden
+ expect(screen.queryByRole('contentinfo'))
+ .not
+ .toBeInTheDocument();
+ });
});
diff --git a/src/discussions/navigation/breadcrumb-menu/BreadcrumbDropdown.jsx b/src/discussions/navigation/breadcrumb-menu/BreadcrumbDropdown.jsx
new file mode 100644
index 00000000..a8a447ad
--- /dev/null
+++ b/src/discussions/navigation/breadcrumb-menu/BreadcrumbDropdown.jsx
@@ -0,0 +1,60 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+
+import { Link } from 'react-router-dom';
+
+import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
+import { Dropdown, DropdownButton } from '@edx/paragon';
+
+import messages from './messages';
+
+function BreadcrumbDropdown({
+ currentItem,
+ intl,
+ showAllPath,
+ items,
+ itemPathFunc,
+ itemLabelFunc,
+ itemActiveFunc,
+}) {
+ const showAllMsg = intl.formatMessage(messages.showAll);
+ return (
+
+
+ {showAllMsg}
+
+ {items?.map(item => (
+
+ {itemLabelFunc(item)}
+
+ ))}
+
+ );
+}
+
+BreadcrumbDropdown.propTypes = {
+ // eslint-disable-next-line react/forbid-prop-types
+ currentItem: PropTypes.object.isRequired,
+ intl: intlShape.isRequired,
+ showAllPath: PropTypes.func.isRequired,
+ // eslint-disable-next-line react/forbid-prop-types
+ items: PropTypes.array.isRequired,
+ itemPathFunc: PropTypes.func.isRequired,
+ itemLabelFunc: PropTypes.func.isRequired,
+ itemActiveFunc: PropTypes.func.isRequired,
+};
+
+export default injectIntl(BreadcrumbDropdown);
diff --git a/src/discussions/navigation/breadcrumb-menu/LegacyBreadcrumbMenu.jsx b/src/discussions/navigation/breadcrumb-menu/LegacyBreadcrumbMenu.jsx
index 7399b846..fabd52f4 100644
--- a/src/discussions/navigation/breadcrumb-menu/LegacyBreadcrumbMenu.jsx
+++ b/src/discussions/navigation/breadcrumb-menu/LegacyBreadcrumbMenu.jsx
@@ -1,10 +1,9 @@
import React from 'react';
import { useSelector } from 'react-redux';
-import { generatePath, useHistory, useRouteMatch } from 'react-router';
+import { useRouteMatch } from 'react-router';
import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
-import { Dropdown, DropdownButton } from '@edx/paragon';
import { Routes } from '../../../data/constants';
import {
@@ -13,10 +12,10 @@ import {
selectTopic,
selectTopicsInCategory,
} from '../../topics/data/selectors';
-import messages from './messages';
+import { discussionsPath } from '../../utils';
+import BreadcrumbDropdown from './BreadcrumbDropdown';
function LegacyBreadcrumbMenu({ intl }) {
- const history = useHistory();
const {
params: {
courseId,
@@ -30,83 +29,59 @@ function LegacyBreadcrumbMenu({ intl }) {
const topicsInCategory = useSelector(selectTopicsInCategory(currentCategory));
const nonCoursewareTopics = useSelector(selectNonCoursewareTopics);
const categories = useSelector(selectCategories);
- const showAllMsg = intl.formatMessage(messages.showAll);
const isNonCoursewareTopic = currentTopic && !currentCategory;
- const navigateToCategory = (categoryId) => {
- if (!categoryId) {
- history.push(generatePath(Routes.TOPICS.ALL, {
- courseId,
- category: categoryId,
- }));
- } else {
- history.push(generatePath(Routes.TOPICS.CATEGORY, {
- courseId,
- category: categoryId,
- }));
- }
- };
- const navigateToTopic = (topicId) => {
- if (!topicId) {
- navigateToCategory(currentCategory);
- } else {
- history.push(generatePath(Routes.TOPICS.TOPIC, {
- courseId,
- topicId,
- }));
- }
- };
-
return (
{isNonCoursewareTopic ? (
-
-
- {showAllMsg}
-
- {nonCoursewareTopics.map(topic => (
-
- {topic.name}
-
- ))}
-
+
item?.name}
+ itemActiveFunc={(topic) => topic?.id === currentTopicId}
+ items={nonCoursewareTopics}
+ showAllPath={discussionsPath(Routes.TOPICS.ALL, {
+ courseId,
+ })}
+ itemPathFunc={(topic) => discussionsPath(Routes.TOPICS.TOPIC, {
+ courseId,
+ topicId: topic.id,
+ })}
+ />
) : (
-
-
- {showAllMsg}
-
- {categories.map(categoryId => (
-
- {categoryId}
-
- ))}
-
+ catId}
+ itemActiveFunc={(catId) => catId === currentCategory}
+ items={categories}
+ showAllPath={discussionsPath(Routes.TOPICS.ALL, {
+ courseId,
+ })}
+ itemPathFunc={(catId) => discussionsPath(Routes.TOPICS.CATEGORY, {
+ courseId,
+ category: catId,
+ })}
+ />
)}
{currentCategory && (
<>
/
-
-
- {showAllMsg}
-
- {topicsInCategory?.map(topic => (
-
- {topic.name}
-
- ))}
-
+ item?.name}
+ itemActiveFunc={(topic) => topic?.id === currentTopicId}
+ items={topicsInCategory}
+ showAllPath={discussionsPath(Routes.TOPICS.CATEGORY, {
+ courseId,
+ category: currentCategory,
+ })}
+ itemPathFunc={(topic) => discussionsPath(Routes.TOPICS.TOPIC, {
+ courseId,
+ topicId: topic.id,
+ })}
+ />
>
)}
diff --git a/src/discussions/navigation/navigation-bar/NavigationBar.jsx b/src/discussions/navigation/navigation-bar/NavigationBar.jsx
index a189de23..72e50d81 100644
--- a/src/discussions/navigation/navigation-bar/NavigationBar.jsx
+++ b/src/discussions/navigation/navigation-bar/NavigationBar.jsx
@@ -1,12 +1,13 @@
import React from 'react';
-import { generatePath, useParams } from 'react-router';
+import { useParams } from 'react-router';
import { NavLink } from 'react-router-dom';
import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
import { Nav } from '@edx/paragon';
import { Routes } from '../../../data/constants';
+import { discussionsPath } from '../../utils';
import messages from './messages';
function NavigationBar({ intl }) {
@@ -30,7 +31,7 @@ function NavigationBar({ intl }) {