Skip to content

Commit 3a7b705

Browse files
authored
fix: user content unavailable content issue for learner (#674)
1 parent 6875165 commit 3a7b705

File tree

7 files changed

+75
-106
lines changed

7 files changed

+75
-106
lines changed
Lines changed: 5 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,21 @@
1-
import React, { useEffect } from 'react';
2-
import PropTypes from 'prop-types';
1+
import React from 'react';
32

43
import classNames from 'classnames';
5-
import { useDispatch, useSelector } from 'react-redux';
4+
import { useSelector } from 'react-redux';
65

76
import { useIntl } from '@edx/frontend-platform/i18n';
87

9-
import fetchTab from './data/thunks';
108
import Tabs from './tabs/Tabs';
119
import messages from './messages';
1210

1311
import './navBar.scss';
1412

15-
const CourseTabsNavigation = ({
16-
activeTab, className, courseId, rootSlug,
17-
}) => {
18-
const dispatch = useDispatch();
13+
const CourseTabsNavigation = () => {
1914
const intl = useIntl();
2015
const tabs = useSelector(state => state.courseTabs.tabs);
2116

22-
useEffect(() => {
23-
dispatch(fetchTab(courseId, rootSlug));
24-
}, [courseId]);
25-
2617
return (
27-
<div id="courseTabsNavigation" className={classNames('course-tabs-navigation px-4 bg-white', className)}>
18+
<div id="courseTabsNavigation" className="course-tabs-navigation px-4 bg-white">
2819
{!!tabs.length && (
2920
<Tabs
3021
className="nav-underline-tabs"
@@ -33,7 +24,7 @@ const CourseTabsNavigation = ({
3324
{tabs.map(({ url, title, slug }) => (
3425
<a
3526
key={slug}
36-
className={classNames('nav-item flex-shrink-0 nav-link', { active: slug === activeTab })}
27+
className={classNames('nav-item flex-shrink-0 nav-link', { active: slug === 'discussion' })}
3728
href={url}
3829
>
3930
{title}
@@ -45,17 +36,4 @@ const CourseTabsNavigation = ({
4536
);
4637
};
4738

48-
CourseTabsNavigation.propTypes = {
49-
activeTab: PropTypes.string,
50-
className: PropTypes.string,
51-
rootSlug: PropTypes.string,
52-
courseId: PropTypes.string.isRequired,
53-
};
54-
55-
CourseTabsNavigation.defaultProps = {
56-
activeTab: undefined,
57-
className: null,
58-
rootSlug: 'outline',
59-
};
60-
6139
export default React.memo(CourseTabsNavigation);

src/components/NavigationBar/data/api.js

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,26 +5,22 @@ import { getApiBaseUrl } from '../../../data/constants';
55

66
export const getCourseMetadataApiUrl = (courseId) => `${getApiBaseUrl()}/api/course_home/course_metadata/${courseId}`;
77

8-
function normalizeCourseHomeCourseMetadata(metadata, rootSlug) {
8+
function normalizeCourseHomeCourseMetadata(metadata) {
99
const data = camelCaseObject(metadata);
1010
return {
1111
...data,
1212
tabs: data.tabs.map(tab => ({
13-
// The API uses "courseware" as a slug for both courseware and the outline tab.
14-
// If needed, we switch it to "outline" here for
15-
// use within the MFE to differentiate between course home and courseware.
16-
slug: tab.tabId === 'courseware' ? rootSlug : tab.tabId,
13+
slug: tab.tabId === 'courseware' ? 'outline' : tab.tabId,
1714
title: tab.title,
1815
url: tab.url,
1916
})),
2017
isMasquerading: data.originalUserIsStaff && !data.isStaff,
2118
};
2219
}
2320

24-
export async function getCourseHomeCourseMetadata(courseId, rootSlug) {
21+
export async function getCourseHomeCourseMetadata(courseId) {
2522
const url = getCourseMetadataApiUrl(courseId);
26-
// don't know the context of adding timezone in url. hence omitting it
27-
// url = appendBrowserTimezoneToUrl(url);
2823
const { data } = await getAuthenticatedHttpClient().get(url);
29-
return normalizeCourseHomeCourseMetadata(data, rootSlug);
24+
25+
return normalizeCourseHomeCourseMetadata(data);
3026
}

src/components/NavigationBar/data/thunks.js

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9,11 +9,11 @@ import {
99
fetchTabSuccess,
1010
} from './slice';
1111

12-
export default function fetchTab(courseId, rootSlug) {
12+
export default function fetchTab(courseId) {
1313
return async (dispatch) => {
1414
dispatch(fetchTabRequest({ courseId }));
1515
try {
16-
const courseHomeCourseMetadata = await getCourseHomeCourseMetadata(courseId, rootSlug);
16+
const courseHomeCourseMetadata = await getCourseHomeCourseMetadata(courseId);
1717
if (!courseHomeCourseMetadata.courseAccess.hasAccess) {
1818
dispatch(fetchTabDenied({ courseId }));
1919
} else {

src/discussions/course-content-unavailable/CourseContentUnavailable.jsx renamed to src/discussions/content-unavailable/ContentUnavailable.jsx

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ import selectCourseTabs from '../../components/NavigationBar/data/selectors';
1313
import { useIsOnDesktop, useIsOnXLDesktop } from '../data/hooks';
1414
import messages from '../messages';
1515

16-
const CourseContentUnavailable = ({ subTitleMessage }) => {
16+
const ContentUnavailable = ({ subTitleMessage }) => {
1717
const intl = useIntl();
1818
const isOnDesktop = useIsOnDesktop();
1919
const isOnXLDesktop = useIsOnXLDesktop();
@@ -31,7 +31,9 @@ const CourseContentUnavailable = ({ subTitleMessage }) => {
3131
})}
3232
>
3333
<ContentUnavailableIcon />
34-
<h3 className="pt-3 font-weight-bold text-primary-500 text-center">{intl.formatMessage(messages.contentUnavailableTitle)}</h3>
34+
<h3 className="pt-3 font-weight-bold text-primary-500 text-center">
35+
{intl.formatMessage(messages.contentUnavailableTitle)}
36+
</h3>
3537
<p className="pb-2 text-gray-500 text-center">{intl.formatMessage(subTitleMessage)}</p>
3638
<Button onClick={redirectToDashboard} variant="outline-dark" className="font-size-14 py-2 px-2.5">
3739
{intl.formatMessage(messages.contentUnavailableAction)}
@@ -41,12 +43,12 @@ const CourseContentUnavailable = ({ subTitleMessage }) => {
4143
);
4244
};
4345

44-
CourseContentUnavailable.propTypes = {
46+
ContentUnavailable.propTypes = {
4547
subTitleMessage: propTypes.shape({
4648
id: propTypes.string,
4749
defaultMessage: propTypes.string,
4850
description: propTypes.string,
4951
}).isRequired,
5052
};
5153

52-
export default React.memo(CourseContentUnavailable);
54+
export default React.memo(ContentUnavailable);

src/discussions/data/hooks.js

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ import { useIntl } from '@edx/frontend-platform/i18n';
1313
import { AppContext } from '@edx/frontend-platform/react';
1414
import { breakpoints, useWindowSize } from '@edx/paragon';
1515

16+
import fetchTab from '../../components/NavigationBar/data/thunks';
1617
import { RequestStatus, Routes } from '../../data/constants';
1718
import { selectTopicsUnderCategory } from '../../data/selectors';
1819
import fetchCourseBlocks from '../../data/thunks';
@@ -79,6 +80,7 @@ export function useCourseDiscussionData(courseId) {
7980
async function fetchBaseData() {
8081
await dispatch(fetchCourseConfig(courseId));
8182
await dispatch(fetchCourseBlocks(courseId, authenticatedUser.username));
83+
await dispatch(fetchTab(courseId));
8284
}
8385

8486
fetchBaseData();

src/discussions/data/selectors.js

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -76,10 +76,12 @@ export const selectIsUserLearner = createSelector(
7676
userIsCourseAdmin,
7777
userIsCourseStaff,
7878
) => (
79-
!userHasModerationPrivileges
80-
&& !userIsGroupTa
81-
&& !userIsStaff
82-
&& !userIsCourseAdmin
83-
&& !userIsCourseStaff
79+
(
80+
!userHasModerationPrivileges
81+
&& !userIsGroupTa
82+
&& !userIsStaff
83+
&& !userIsCourseAdmin
84+
&& !userIsCourseStaff
85+
) || false
8486
),
8587
);

src/discussions/discussions-home/DiscussionsHome.jsx

Lines changed: 48 additions & 59 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,10 @@ import { LearningHeader as Header } from '@edx/frontend-component-header';
1212

1313
import { Spinner } from '../../components';
1414
import selectCourseTabs from '../../components/NavigationBar/data/selectors';
15-
import { LOADING } from '../../components/NavigationBar/data/slice';
15+
import { LOADED } from '../../components/NavigationBar/data/slice';
1616
import { ALL_ROUTES, DiscussionProvider, Routes as ROUTES } from '../../data/constants';
1717
import DiscussionContext from '../common/context';
18-
import ContentUnavailable from '../course-content-unavailable/CourseContentUnavailable';
18+
import ContentUnavailable from '../content-unavailable/ContentUnavailable';
1919
import {
2020
useCourseDiscussionData, useIsOnDesktop, useRedirectToThread, useSidebarVisible,
2121
} from '../data/hooks';
@@ -80,55 +80,48 @@ const DiscussionsHome = () => {
8080
return (
8181
<Suspense fallback={(<Spinner />)}>
8282
<DiscussionContext.Provider value={discussionContextValue}>
83-
{!enableInContextSidebar && (
84-
<Header courseOrg={org} courseNumber={courseNumber} courseTitle={courseTitle} />
85-
)}
83+
{!enableInContextSidebar && (<Header courseOrg={org} courseNumber={courseNumber} courseTitle={courseTitle} />)}
8684
<main className="container-fluid d-flex flex-column p-0 w-100" id="main" tabIndex="-1">
87-
{!enableInContextSidebar && <CourseTabsNavigation activeTab="discussion" courseId={courseId} />}
88-
{(isEnrolled || !isUserLearner || enableInContextSidebar) && (
89-
<div
90-
className={classNames('header-action-bar bg-white position-sticky', {
91-
'shadow-none border-light-300 border-bottom': enableInContextSidebar,
92-
})}
93-
ref={postActionBarRef}
94-
>
85+
{!enableInContextSidebar && <CourseTabsNavigation />}
86+
{(isEnrolled || !isUserLearner) && (
9587
<div
96-
className={classNames('d-flex flex-row justify-content-between navbar fixed-top', {
97-
'pl-4 pr-2 py-0': enableInContextSidebar,
88+
className={classNames('header-action-bar bg-white position-sticky', {
89+
'shadow-none border-light-300 border-bottom': enableInContextSidebar,
9890
})}
91+
ref={postActionBarRef}
9992
>
100-
{!enableInContextSidebar && (
101-
<NavigationBar />
102-
)}
103-
<PostActionsBar />
93+
<div className={classNames('d-flex flex-row justify-content-between navbar fixed-top', {
94+
'pl-4 pr-2 py-0': enableInContextSidebar,
95+
})}
96+
>
97+
{!enableInContextSidebar && (<NavigationBar />)}
98+
<PostActionsBar />
99+
</div>
100+
<DiscussionsRestrictionBanner />
104101
</div>
105-
<DiscussionsRestrictionBanner />
106-
</div>
107102
)}
108-
109103
{provider === DiscussionProvider.LEGACY && (
110-
<Suspense fallback={(<Spinner />)}>
111-
<Routes>
112-
{[
113-
ROUTES.TOPICS.CATEGORY,
114-
ROUTES.TOPICS.CATEGORY_POST,
115-
ROUTES.TOPICS.CATEGORY_POST_EDIT,
116-
ROUTES.TOPICS.TOPIC,
117-
ROUTES.TOPICS.TOPIC_POST,
118-
ROUTES.TOPICS.TOPIC_POST_EDIT,
119-
].map((route) => (
120-
<Route
121-
key={route}
122-
path={route}
123-
element={<LegacyBreadcrumbMenu />}
124-
/>
125-
))}
126-
</Routes>
127-
</Suspense>
104+
<Suspense fallback={(<Spinner />)}>
105+
<Routes>
106+
{[
107+
ROUTES.TOPICS.CATEGORY,
108+
ROUTES.TOPICS.CATEGORY_POST,
109+
ROUTES.TOPICS.CATEGORY_POST_EDIT,
110+
ROUTES.TOPICS.TOPIC,
111+
ROUTES.TOPICS.TOPIC_POST,
112+
ROUTES.TOPICS.TOPIC_POST_EDIT,
113+
].map((route) => (
114+
<Route
115+
key={route}
116+
path={route}
117+
element={<LegacyBreadcrumbMenu />}
118+
/>
119+
))}
120+
</Routes>
121+
</Suspense>
128122
)}
129-
{(courseStatus !== LOADING || enableInContextSidebar) && (
130-
<div>
131-
{ isEnrolled === false && isUserLearner ? (
123+
{(courseStatus === LOADED) && (
124+
!isEnrolled && isUserLearner ? (
132125
<Suspense fallback={(<Spinner />)}>
133126
<Routes>
134127
{ALL_ROUTES.map((route) => (
@@ -140,18 +133,17 @@ const DiscussionsHome = () => {
140133
))}
141134
</Routes>
142135
</Suspense>
143-
)
144-
: (
145-
<div className="d-flex flex-row position-relative">
146-
<Suspense fallback={(<Spinner />)}>
147-
<DiscussionSidebar displaySidebar={displaySidebar} postActionBarRef={postActionBarRef} />
148-
</Suspense>
149-
{displayContentArea && (
136+
) : (
137+
<div className="d-flex flex-row position-relative">
138+
<Suspense fallback={(<Spinner />)}>
139+
<DiscussionSidebar displaySidebar={displaySidebar} postActionBarRef={postActionBarRef} />
140+
</Suspense>
141+
{displayContentArea && (
150142
<Suspense fallback={(<Spinner />)}>
151143
<DiscussionContent />
152144
</Suspense>
153-
)}
154-
{!displayContentArea && (
145+
)}
146+
{!displayContentArea && (
155147
<Routes>
156148
<>
157149
{ROUTES.TOPICS.PATH.map(route => (
@@ -176,14 +168,11 @@ const DiscussionsHome = () => {
176168
<Route path={ROUTES.LEARNERS.PATH} element={<EmptyLearners />} />
177169
</>
178170
</Routes>
179-
)}
180-
</div>
181-
)}
182-
</div>
183-
)}
184-
{!enableInContextSidebar && (
185-
<DiscussionsProductTour />
171+
)}
172+
</div>
173+
)
186174
)}
175+
{!enableInContextSidebar && (<DiscussionsProductTour />)}
187176
</main>
188177
{!enableInContextSidebar && <Footer />}
189178
</DiscussionContext.Provider>

0 commit comments

Comments
 (0)