Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

fix: Use Paragon Tab Component #1448

Open
wants to merge 4 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion src/constants.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,10 @@ export const DECODE_ROUTES = {
HOME: '/course/:courseId/home',
LIVE: '/course/:courseId/live',
DATES: '/course/:courseId/dates',
DISCUSSION: '/course/:courseId/discussion/:path/*',
DISCUSSION_ROUTES: [
'/course/:courseId/discussion/:path/*',
'/course/:courseId/discussion',
],
PROGRESS: [
'/course/:courseId/progress/:targetUserId/',
'/course/:courseId/progress',
Expand Down
2 changes: 1 addition & 1 deletion src/course-home/dates-tab/timeline/Timeline.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ const Timeline = () => {
const now = new Date();
let foundNextDue = false;
let foundToday = false;
courseDateBlocks.forEach(courseDateBlock => {
courseDateBlocks?.forEach(courseDateBlock => {
const dateInfo = { ...courseDateBlock };
const parsedDate = new Date(dateInfo.date);

Expand Down
24 changes: 4 additions & 20 deletions src/course-home/discussion-tab/DiscussionTab.jsx
Original file line number Diff line number Diff line change
@@ -1,33 +1,17 @@
import { getConfig } from '@edx/frontend-platform';
import { injectIntl } from '@edx/frontend-platform/i18n';
import React, { useState } from 'react';
import { useState } from 'react';
import { useSelector } from 'react-redux';
import { useParams, generatePath, useNavigate } from 'react-router-dom';
import { useIFrameHeight, useIFramePluginEvents } from '../../generic/hooks';
import { useParams } from 'react-router-dom';

const DiscussionTab = () => {
const { courseId } = useSelector(state => state.courseHome);
const { path } = useParams();
const [originalPath] = useState(path);
const navigate = useNavigate();

const [, iFrameHeight] = useIFrameHeight();
useIFramePluginEvents({
'discussions.navigate': (payload) => {
const basePath = generatePath('/course/:courseId/discussion', { courseId });
navigate(`${basePath}/${payload.path}`);
},
});
const discussionsUrl = `${getConfig().DISCUSSIONS_MFE_BASE_URL}/${courseId}/${originalPath}`;
return (
<iframe
src={discussionsUrl}
className="d-flex w-100 border-0"
height={iFrameHeight}
style={{ minHeight: '60rem' }}
title="discussion"
/>
);
window.location.href = discussionsUrl;
return (<></>);

Check warning on line 14 in src/course-home/discussion-tab/DiscussionTab.jsx

View check run for this annotation

Codecov / codecov/patch

src/course-home/discussion-tab/DiscussionTab.jsx#L13-L14

Added lines #L13 - L14 were not covered by tests
};

DiscussionTab.propTypes = {};
Expand Down
53 changes: 25 additions & 28 deletions src/course-home/discussion-tab/DiscussionTab.test.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,61 +6,58 @@ import MockAdapter from 'axios-mock-adapter';
import React from 'react';
import { Route, Routes } from 'react-router-dom';
import { Factory } from 'rosie';
import CoursewarePage from '@src/pages/courseware/components';
import DecodePageRoute from '@src/decode-page-route';
import { initializeMockApp, waitFor } from '@src/setupTest';
import { appendBrowserTimezoneToUrl } from '@src/utils';
import { UserMessagesProvider } from '../../generic/user-messages';
import {
initializeMockApp, messageEvent, screen, waitFor,
} from '../../setupTest';
import initializeStore from '../../store';
import { TabContainer } from '../../tab-page';
import { appendBrowserTimezoneToUrl } from '../../utils';
import { fetchDiscussionTab } from '../data/thunks';
import DiscussionTab from './DiscussionTab';

initializeMockApp();
jest.mock('@edx/frontend-platform/analytics');

describe('DiscussionTab', () => {
let axiosMock;
let store;
let component;
let courseMetadataUrl;

const courseMetadata = Factory.build('courseHomeMetadata', { user_timezone: 'America/New_York' });
const { id: courseId } = courseMetadata;

beforeEach(() => {
axiosMock = new MockAdapter(getAuthenticatedHttpClient());
store = initializeStore();
component = (

courseMetadataUrl = `${getConfig().LMS_BASE_URL}/api/course_home/course_metadata/${courseId}`;
courseMetadataUrl = appendBrowserTimezoneToUrl(courseMetadataUrl);

axiosMock.onGet(courseMetadataUrl).reply(200, courseMetadata);
history.push(`/course/${courseId}/discussion`); // so tab can pull course id from url

const component = (
<AppProvider store={store}>
<UserMessagesProvider>
<Routes>
<Route
path="/course/:courseId/discussion"
element={(
<TabContainer tab="discussion" fetch={fetchDiscussionTab} slice="courseHome">
<DiscussionTab />
</TabContainer>
)}
<DecodePageRoute>
<CoursewarePage key="courseHome" activeKey="discussion" />
</DecodePageRoute>
)}
/>
</Routes>
</UserMessagesProvider>
</AppProvider>
);
});

const courseMetadata = Factory.build('courseHomeMetadata', { user_timezone: 'America/New_York' });
const { id: courseId } = courseMetadata;

let courseMetadataUrl = `${getConfig().LMS_BASE_URL}/api/course_home/course_metadata/${courseId}`;
courseMetadataUrl = appendBrowserTimezoneToUrl(courseMetadataUrl);

beforeEach(() => {
axiosMock.onGet(courseMetadataUrl).reply(200, courseMetadata);
history.push(`/course/${courseId}/discussion`); // so tab can pull course id from url

render(component);
});

it('resizes when it gets a size hint from iframe', async () => {
window.postMessage({ ...messageEvent, payload: { height: 1234 } }, '*');
await waitFor(() => expect(screen.getByTitle('discussion'))
.toHaveAttribute('height', String(1234)));
it('Validate discussion component url', async () => {
// Simulate the redirect logic within your component
await waitFor(() => {
expect(window.location.href).toBe(`http://localhost/course/${courseId}/discussion`);
});
});
});
2 changes: 1 addition & 1 deletion src/course-home/outline-tab/OutlineTab.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -170,7 +170,7 @@ const OutlineTab = ({ intl }) => {
</div>
</div>
<ol id="courseHome-outline" className="list-unstyled">
{courses[rootCourseId].sectionIds.map((sectionId) => (
{courses && courses[rootCourseId].sectionIds.map((sectionId) => (
<Section
key={sectionId}
courseId={courseId}
Expand Down
66 changes: 24 additions & 42 deletions src/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,33 +2,26 @@
import 'regenerator-runtime/runtime';

import {
APP_INIT_ERROR, APP_READY, subscribe, initialize,
mergeConfig,
getConfig,
APP_INIT_ERROR, APP_READY, getConfig, initialize, mergeConfig, subscribe,
} from '@edx/frontend-platform';
import { AppProvider, ErrorPage, PageWrap } from '@edx/frontend-platform/react';
import React from 'react';
import ReactDOM from 'react-dom';
import { Routes, Route } from 'react-router-dom';
import { Route, Routes } from 'react-router-dom';

import { Helmet } from 'react-helmet';
import { fetchDiscussionTab, fetchLiveTab } from './course-home/data/thunks';
import DiscussionTab from './course-home/discussion-tab/DiscussionTab';
import CoursewarePage from '@src/pages/courseware/components';
import { fetchLiveTab } from './course-home/data/thunks';

import messages from './i18n';
import { UserMessagesProvider } from './generic/user-messages';

import './index.scss';
import OutlineTab from './course-home/outline-tab';
import { CourseExit } from './courseware/course/course-exit';
import CoursewareContainer from './courseware';
import CoursewareRedirectLandingPage from './courseware/CoursewareRedirectLandingPage';
import DatesTab from './course-home/dates-tab';
import GoalUnsubscribe from './course-home/goal-unsubscribe';
import ProgressTab from './course-home/progress-tab/ProgressTab';
import { TabContainer } from './tab-page';

import { fetchDatesTab, fetchOutlineTab, fetchProgressTab } from './course-home/data';
import { fetchCourse } from './courseware/data';
import initializeStore from './store';
import NoticesProvider from './generic/notices';
Expand All @@ -48,22 +41,20 @@
<NoticesProvider>
<UserMessagesProvider>
<Routes>
<Route path={ROUTES.UNSUBSCRIBE} element={<PageWrap><GoalUnsubscribe /></PageWrap>} />
<Route path={ROUTES.REDIRECT} element={<PageWrap><CoursewareRedirectLandingPage /></PageWrap>} />
<Route
path={DECODE_ROUTES.ACCESS_DENIED}
element={<DecodePageRoute><CourseAccessErrorPage /></DecodePageRoute>}
/>
<Route
path={DECODE_ROUTES.HOME}
element={(
<DecodePageRoute>
<TabContainer tab="outline" fetch={fetchOutlineTab} slice="courseHome">
<OutlineTab />
</TabContainer>
<CoursewarePage key="courseHome" activeKey="outline" />
</DecodePageRoute>
)}
/>
<Route path={ROUTES.UNSUBSCRIBE} element={<PageWrap><GoalUnsubscribe /></PageWrap>} />
<Route path={ROUTES.REDIRECT} element={<PageWrap><CoursewareRedirectLandingPage /></PageWrap>} />
<Route
path={DECODE_ROUTES.ACCESS_DENIED}
element={<DecodePageRoute><CourseAccessErrorPage /></DecodePageRoute>}
/>
<Route
path={DECODE_ROUTES.LIVE}
element={(
Expand All @@ -78,38 +69,29 @@
path={DECODE_ROUTES.DATES}
element={(
<DecodePageRoute>
<TabContainer tab="dates" fetch={fetchDatesTab} slice="courseHome">
<DatesTab />
</TabContainer>
</DecodePageRoute>
)}
/>
<Route
path={DECODE_ROUTES.DISCUSSION}
element={(
<DecodePageRoute>
<TabContainer tab="discussion" fetch={fetchDiscussionTab} slice="courseHome">
<DiscussionTab />
</TabContainer>
<CoursewarePage key="dates" activeKey="dates" />
</DecodePageRoute>
)}
/>
{DECODE_ROUTES.DISCUSSION_ROUTES.map(r => (

Check warning on line 76 in src/index.jsx

View check run for this annotation

Codecov / codecov/patch

src/index.jsx#L76

Added line #L76 was not covered by tests
<Route
path={r}
element={(
<DecodePageRoute>
<CoursewarePage key="courseHome" activeKey="discussion" />
</DecodePageRoute>
)}
/>
))}
{DECODE_ROUTES.PROGRESS.map((route) => (
<Route
key={route}
path={route}
element={(
<DecodePageRoute>
<TabContainer
tab="progress"
fetch={fetchProgressTab}
slice="courseHome"
isProgressTab
>
<ProgressTab />
</TabContainer>
<CoursewarePage key="courseHome" activeKey="progress" />
</DecodePageRoute>
)}
)}
/>
))}
<Route
Expand Down
Loading
Loading