Merge branch 'openedx:master' into master
This commit is contained in:
14
package-lock.json
generated
14
package-lock.json
generated
@@ -14,7 +14,7 @@
|
||||
"@edx/frontend-component-footer": "^14.6.0",
|
||||
"@edx/frontend-component-header": "^6.2.0",
|
||||
"@edx/frontend-lib-learning-assistant": "^2.20.0",
|
||||
"@edx/frontend-lib-special-exams": "^3.5.0",
|
||||
"@edx/frontend-lib-special-exams": "^4.0.0",
|
||||
"@edx/frontend-platform": "^8.3.1",
|
||||
"@edx/openedx-atlas": "^0.7.0",
|
||||
"@edx/react-unit-test-utils": "^4.0.0",
|
||||
@@ -2287,9 +2287,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/@edx/frontend-lib-special-exams": {
|
||||
"version": "3.5.0",
|
||||
"resolved": "https://registry.npmjs.org/@edx/frontend-lib-special-exams/-/frontend-lib-special-exams-3.5.0.tgz",
|
||||
"integrity": "sha512-lRKD3K+XAuoKAaxbZxb7QLTWkSlV9yIy08XflYoHh/weClesVTETU3+NtJ5YRsC/kYHZrzSYIpMZnBnkKTGTww==",
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/@edx/frontend-lib-special-exams/-/frontend-lib-special-exams-4.0.0.tgz",
|
||||
"integrity": "sha512-mJdrxebdKO9NxDFkQZ1vyWVUvWCk393pIVHJyz9vH42Kvn08LC5db8/gYk37srCfsA4Dl78pMLa408CoT14JMA==",
|
||||
"license": "AGPL-3.0",
|
||||
"dependencies": {
|
||||
"@fortawesome/fontawesome-svg-core": "1.2.34",
|
||||
@@ -7884,9 +7884,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/caniuse-lite": {
|
||||
"version": "1.0.30001720",
|
||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001720.tgz",
|
||||
"integrity": "sha512-Ec/2yV2nNPwb4DnTANEV99ZWwm3ZWfdlfkQbWSDDt+PsXEVYwlhPH8tdMaPunYTKKmz7AnHi2oNEi1GcmKCD8g==",
|
||||
"version": "1.0.30001721",
|
||||
"resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30001721.tgz",
|
||||
"integrity": "sha512-cOuvmUVtKrtEaoKiO0rSc29jcjwMwX5tOHDy4MgVFEWiUXj4uBMJkwI8MDySkgXidpMiHUcviogAvFi4pA2hDQ==",
|
||||
"funding": [
|
||||
{
|
||||
"type": "opencollective",
|
||||
|
||||
@@ -38,7 +38,7 @@
|
||||
"@edx/frontend-component-footer": "^14.6.0",
|
||||
"@edx/frontend-component-header": "^6.2.0",
|
||||
"@edx/frontend-lib-learning-assistant": "^2.20.0",
|
||||
"@edx/frontend-lib-special-exams": "^3.5.0",
|
||||
"@edx/frontend-lib-special-exams": "^4.0.0",
|
||||
"@edx/frontend-platform": "^8.3.1",
|
||||
"@edx/openedx-atlas": "^0.7.0",
|
||||
"@edx/react-unit-test-utils": "^4.0.0",
|
||||
@@ -98,4 +98,4 @@
|
||||
],
|
||||
"normalizeFilenames": "^.+?(\\..+?)\\.\\w+$"
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -34,188 +34,192 @@ exports[`app registry subscribe: APP_READY. links App to root element 1`] = `
|
||||
<PathFixesProvider>
|
||||
<NoticesProvider>
|
||||
<UserMessagesProvider>
|
||||
<Routes>
|
||||
<Route
|
||||
element={
|
||||
<PageWrap>
|
||||
<Page Not Found />
|
||||
</PageWrap>
|
||||
}
|
||||
path="*"
|
||||
/>
|
||||
<Route
|
||||
element={
|
||||
<PageWrap>
|
||||
<Goal Unsubscribe />
|
||||
</PageWrap>
|
||||
}
|
||||
path="/goal-unsubscribe/:token"
|
||||
/>
|
||||
<Route
|
||||
element={
|
||||
<PageWrap>
|
||||
<Courseware Redirect Landing Page />
|
||||
</PageWrap>
|
||||
}
|
||||
path="/redirect/*"
|
||||
/>
|
||||
<Route
|
||||
element={
|
||||
<PageWrap>
|
||||
<Preferences Unsubscribe />
|
||||
</PageWrap>
|
||||
}
|
||||
path="/preferences-unsubscribe/:userToken/:updatePatch"
|
||||
/>
|
||||
<Route
|
||||
element={
|
||||
<DecodePageRoute>
|
||||
<Course Access Error Page />
|
||||
</DecodePageRoute>
|
||||
}
|
||||
path="/course/:courseId/access-denied"
|
||||
/>
|
||||
<Route
|
||||
element={
|
||||
<DecodePageRoute>
|
||||
<Tab Container
|
||||
fetch={[Function]}
|
||||
slice="courseHome"
|
||||
tab="outline"
|
||||
>
|
||||
<Outline Tab />
|
||||
</Tab Container>
|
||||
</DecodePageRoute>
|
||||
}
|
||||
path="/course/:courseId/home"
|
||||
/>
|
||||
<Route
|
||||
element={
|
||||
<DecodePageRoute>
|
||||
<Tab Container
|
||||
fetch={[Function]}
|
||||
slice="courseHome"
|
||||
tab="lti_live"
|
||||
>
|
||||
<Live Tab />
|
||||
</Tab Container>
|
||||
</DecodePageRoute>
|
||||
}
|
||||
path="/course/:courseId/live"
|
||||
/>
|
||||
<Route
|
||||
element={
|
||||
<DecodePageRoute>
|
||||
<Tab Container
|
||||
fetch={[Function]}
|
||||
slice="courseHome"
|
||||
tab="dates"
|
||||
>
|
||||
<Dates Tab />
|
||||
</Tab Container>
|
||||
</DecodePageRoute>
|
||||
}
|
||||
path="/course/:courseId/dates"
|
||||
/>
|
||||
<Route
|
||||
element={
|
||||
<DecodePageRoute>
|
||||
<Tab Container
|
||||
fetch={[Function]}
|
||||
slice="courseHome"
|
||||
tab="discussion"
|
||||
>
|
||||
<Discussion Tab />
|
||||
</Tab Container>
|
||||
</DecodePageRoute>
|
||||
}
|
||||
path="/course/:courseId/discussion/:path/*"
|
||||
/>
|
||||
<Route
|
||||
element={
|
||||
<DecodePageRoute>
|
||||
<Tab Container
|
||||
fetch={[Function]}
|
||||
isProgressTab={true}
|
||||
slice="courseHome"
|
||||
tab="progress"
|
||||
>
|
||||
<Progress Tab />
|
||||
</Tab Container>
|
||||
</DecodePageRoute>
|
||||
}
|
||||
path="/course/:courseId/progress/:targetUserId/"
|
||||
/>
|
||||
<Route
|
||||
element={
|
||||
<DecodePageRoute>
|
||||
<Tab Container
|
||||
fetch={[Function]}
|
||||
isProgressTab={true}
|
||||
slice="courseHome"
|
||||
tab="progress"
|
||||
>
|
||||
<Progress Tab />
|
||||
</Tab Container>
|
||||
</DecodePageRoute>
|
||||
}
|
||||
path="/course/:courseId/progress"
|
||||
/>
|
||||
<Route
|
||||
element={
|
||||
<DecodePageRoute>
|
||||
<Tab Container
|
||||
fetch={[Function]}
|
||||
slice="courseware"
|
||||
tab="courseware"
|
||||
>
|
||||
<Course Exit />
|
||||
</Tab Container>
|
||||
</DecodePageRoute>
|
||||
}
|
||||
path="/course/:courseId/course-end"
|
||||
/>
|
||||
<Route
|
||||
element={
|
||||
<DecodePageRoute>
|
||||
<Courseware Container />
|
||||
</DecodePageRoute>
|
||||
}
|
||||
path="/course/:courseId/:sequenceId/:unitId"
|
||||
/>
|
||||
<Route
|
||||
element={
|
||||
<DecodePageRoute>
|
||||
<Courseware Container />
|
||||
</DecodePageRoute>
|
||||
}
|
||||
path="/course/:courseId/:sequenceId"
|
||||
/>
|
||||
<Route
|
||||
element={
|
||||
<DecodePageRoute>
|
||||
<Courseware Container />
|
||||
</DecodePageRoute>
|
||||
}
|
||||
path="/course/:courseId"
|
||||
/>
|
||||
<Route
|
||||
element={
|
||||
<DecodePageRoute>
|
||||
<Courseware Container />
|
||||
</DecodePageRoute>
|
||||
}
|
||||
path="/preview/course/:courseId/:sequenceId/:unitId"
|
||||
/>
|
||||
<Route
|
||||
element={
|
||||
<DecodePageRoute>
|
||||
<Courseware Container />
|
||||
</DecodePageRoute>
|
||||
}
|
||||
path="/preview/course/:courseId/:sequenceId"
|
||||
/>
|
||||
</Routes>
|
||||
<div
|
||||
className="app-container"
|
||||
>
|
||||
<Routes>
|
||||
<Route
|
||||
element={
|
||||
<PageWrap>
|
||||
<Page Not Found />
|
||||
</PageWrap>
|
||||
}
|
||||
path="*"
|
||||
/>
|
||||
<Route
|
||||
element={
|
||||
<PageWrap>
|
||||
<Goal Unsubscribe />
|
||||
</PageWrap>
|
||||
}
|
||||
path="/goal-unsubscribe/:token"
|
||||
/>
|
||||
<Route
|
||||
element={
|
||||
<PageWrap>
|
||||
<Courseware Redirect Landing Page />
|
||||
</PageWrap>
|
||||
}
|
||||
path="/redirect/*"
|
||||
/>
|
||||
<Route
|
||||
element={
|
||||
<PageWrap>
|
||||
<Preferences Unsubscribe />
|
||||
</PageWrap>
|
||||
}
|
||||
path="/preferences-unsubscribe/:userToken/:updatePatch"
|
||||
/>
|
||||
<Route
|
||||
element={
|
||||
<DecodePageRoute>
|
||||
<Course Access Error Page />
|
||||
</DecodePageRoute>
|
||||
}
|
||||
path="/course/:courseId/access-denied"
|
||||
/>
|
||||
<Route
|
||||
element={
|
||||
<DecodePageRoute>
|
||||
<Tab Container
|
||||
fetch={[Function]}
|
||||
slice="courseHome"
|
||||
tab="outline"
|
||||
>
|
||||
<Outline Tab />
|
||||
</Tab Container>
|
||||
</DecodePageRoute>
|
||||
}
|
||||
path="/course/:courseId/home"
|
||||
/>
|
||||
<Route
|
||||
element={
|
||||
<DecodePageRoute>
|
||||
<Tab Container
|
||||
fetch={[Function]}
|
||||
slice="courseHome"
|
||||
tab="lti_live"
|
||||
>
|
||||
<Live Tab />
|
||||
</Tab Container>
|
||||
</DecodePageRoute>
|
||||
}
|
||||
path="/course/:courseId/live"
|
||||
/>
|
||||
<Route
|
||||
element={
|
||||
<DecodePageRoute>
|
||||
<Tab Container
|
||||
fetch={[Function]}
|
||||
slice="courseHome"
|
||||
tab="dates"
|
||||
>
|
||||
<Dates Tab />
|
||||
</Tab Container>
|
||||
</DecodePageRoute>
|
||||
}
|
||||
path="/course/:courseId/dates"
|
||||
/>
|
||||
<Route
|
||||
element={
|
||||
<DecodePageRoute>
|
||||
<Tab Container
|
||||
fetch={[Function]}
|
||||
slice="courseHome"
|
||||
tab="discussion"
|
||||
>
|
||||
<Discussion Tab />
|
||||
</Tab Container>
|
||||
</DecodePageRoute>
|
||||
}
|
||||
path="/course/:courseId/discussion/:path/*"
|
||||
/>
|
||||
<Route
|
||||
element={
|
||||
<DecodePageRoute>
|
||||
<Tab Container
|
||||
fetch={[Function]}
|
||||
isProgressTab={true}
|
||||
slice="courseHome"
|
||||
tab="progress"
|
||||
>
|
||||
<Progress Tab />
|
||||
</Tab Container>
|
||||
</DecodePageRoute>
|
||||
}
|
||||
path="/course/:courseId/progress/:targetUserId/"
|
||||
/>
|
||||
<Route
|
||||
element={
|
||||
<DecodePageRoute>
|
||||
<Tab Container
|
||||
fetch={[Function]}
|
||||
isProgressTab={true}
|
||||
slice="courseHome"
|
||||
tab="progress"
|
||||
>
|
||||
<Progress Tab />
|
||||
</Tab Container>
|
||||
</DecodePageRoute>
|
||||
}
|
||||
path="/course/:courseId/progress"
|
||||
/>
|
||||
<Route
|
||||
element={
|
||||
<DecodePageRoute>
|
||||
<Tab Container
|
||||
fetch={[Function]}
|
||||
slice="courseware"
|
||||
tab="courseware"
|
||||
>
|
||||
<Course Exit />
|
||||
</Tab Container>
|
||||
</DecodePageRoute>
|
||||
}
|
||||
path="/course/:courseId/course-end"
|
||||
/>
|
||||
<Route
|
||||
element={
|
||||
<DecodePageRoute>
|
||||
<Courseware Container />
|
||||
</DecodePageRoute>
|
||||
}
|
||||
path="/course/:courseId/:sequenceId/:unitId"
|
||||
/>
|
||||
<Route
|
||||
element={
|
||||
<DecodePageRoute>
|
||||
<Courseware Container />
|
||||
</DecodePageRoute>
|
||||
}
|
||||
path="/course/:courseId/:sequenceId"
|
||||
/>
|
||||
<Route
|
||||
element={
|
||||
<DecodePageRoute>
|
||||
<Courseware Container />
|
||||
</DecodePageRoute>
|
||||
}
|
||||
path="/course/:courseId"
|
||||
/>
|
||||
<Route
|
||||
element={
|
||||
<DecodePageRoute>
|
||||
<Courseware Container />
|
||||
</DecodePageRoute>
|
||||
}
|
||||
path="/preview/course/:courseId/:sequenceId/:unitId"
|
||||
/>
|
||||
<Route
|
||||
element={
|
||||
<DecodePageRoute>
|
||||
<Courseware Container />
|
||||
</DecodePageRoute>
|
||||
}
|
||||
path="/preview/course/:courseId/:sequenceId"
|
||||
/>
|
||||
</Routes>
|
||||
</div>
|
||||
</UserMessagesProvider>
|
||||
</NoticesProvider>
|
||||
</PathFixesProvider>
|
||||
|
||||
@@ -54,6 +54,8 @@ const SidebarProvider: React.FC<Props> = ({
|
||||
}, [courseId]);
|
||||
|
||||
useEffect(() => {
|
||||
window.sessionStorage.setItem('hideCourseOutlineSidebar', 'true');
|
||||
window.sessionStorage.setItem(`notificationTrayStatus.${courseId}`, 'open');
|
||||
setHideDiscussionbar(!isDiscussionbarAvailable);
|
||||
setHideNotificationbar(!isNotificationbarAvailable);
|
||||
if (initialSidebar && currentSidebar !== initialSidebar) {
|
||||
|
||||
@@ -1,11 +1,13 @@
|
||||
import React from 'react';
|
||||
|
||||
import { fireEvent } from '@testing-library/react';
|
||||
import MockAdapter from 'axios-mock-adapter';
|
||||
|
||||
import { getConfig } from '@edx/frontend-platform';
|
||||
import { getAuthenticatedHttpClient } from '@edx/frontend-platform/auth';
|
||||
import { sendTrackEvent } from '@edx/frontend-platform/analytics';
|
||||
import { getAuthenticatedHttpClient } from '@edx/frontend-platform/auth';
|
||||
|
||||
import { getSessionStorage, setSessionStorage } from '../../../../../../data/sessionStorage';
|
||||
import {
|
||||
initializeMockApp, initializeTestStore, render, screen,
|
||||
} from '../../../../../../setupTest';
|
||||
@@ -14,11 +16,19 @@ import { buildTopicsFromUnits } from '../../../../../data/__factories__/discussi
|
||||
import { getCourseDiscussionTopics } from '../../../../../data/thunks';
|
||||
import SidebarContext from '../../../SidebarContext';
|
||||
import DiscussionsNotificationsSidebar from '../DiscussionsNotificationsSidebar';
|
||||
import DiscussionsNotificationsTrigger from '../DiscussionsNotificationsTrigger';
|
||||
import DiscussionsWidget from './DiscussionsWidget';
|
||||
|
||||
initializeMockApp();
|
||||
jest.mock('@edx/frontend-platform/analytics');
|
||||
|
||||
jest.mock('../../../../../../data/sessionStorage', () => ({
|
||||
getSessionStorage: jest.fn(),
|
||||
setSessionStorage: jest.fn(),
|
||||
}));
|
||||
|
||||
const onClickMock = jest.fn();
|
||||
|
||||
describe('DiscussionsWidget', () => {
|
||||
let axiosMock;
|
||||
let mockData;
|
||||
@@ -81,4 +91,34 @@ describe('DiscussionsWidget', () => {
|
||||
expect(screen.queryByText('Back to course')).toBeInTheDocument();
|
||||
expect(sendTrackEvent).toHaveBeenCalledTimes(1);
|
||||
});
|
||||
|
||||
it('should open notification tray if closed', () => {
|
||||
(getSessionStorage as jest.Mock).mockReturnValue('closed');
|
||||
|
||||
renderWithProvider(() => <DiscussionsNotificationsTrigger onClick={onClickMock} />);
|
||||
|
||||
const button = screen.getByRole('button');
|
||||
fireEvent.click(button);
|
||||
|
||||
expect(setSessionStorage).toHaveBeenCalledWith(
|
||||
`notificationTrayStatus.${courseId}`,
|
||||
'open',
|
||||
);
|
||||
expect(onClickMock).toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it('should close notification tray if open', () => {
|
||||
(getSessionStorage as jest.Mock).mockReturnValue('open');
|
||||
|
||||
renderWithProvider(() => <DiscussionsNotificationsTrigger onClick={onClickMock} />);
|
||||
|
||||
const button = screen.getByRole('button');
|
||||
fireEvent.click(button);
|
||||
|
||||
expect(setSessionStorage).toHaveBeenCalledWith(
|
||||
`notificationTrayStatus.${courseId}`,
|
||||
'open',
|
||||
);
|
||||
expect(onClickMock).toHaveBeenCalled();
|
||||
});
|
||||
});
|
||||
|
||||
@@ -218,18 +218,20 @@ const Sequence = ({
|
||||
|
||||
if (sequenceStatus === 'loaded') {
|
||||
return (
|
||||
<div>
|
||||
<SequenceExamWrapper
|
||||
sequence={sequence}
|
||||
courseId={courseId}
|
||||
isStaff={isStaff}
|
||||
originalUserIsStaff={originalUserIsStaff}
|
||||
canAccessProctoredExams={canAccessProctoredExams}
|
||||
>
|
||||
{defaultContent}
|
||||
</SequenceExamWrapper>
|
||||
<>
|
||||
<div className="d-flex flex-column flex-grow-1 justify-content-center">
|
||||
<SequenceExamWrapper
|
||||
sequence={sequence}
|
||||
courseId={courseId}
|
||||
isStaff={isStaff}
|
||||
originalUserIsStaff={originalUserIsStaff}
|
||||
canAccessProctoredExams={canAccessProctoredExams}
|
||||
>
|
||||
{defaultContent}
|
||||
</SequenceExamWrapper>
|
||||
</div>
|
||||
<CourseLicense license={license || undefined} />
|
||||
</div>
|
||||
</>
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,14 +1,12 @@
|
||||
.outline-sidebar-wrapper {
|
||||
width: 32.125rem;
|
||||
max-width: 100%;
|
||||
overflow: auto;
|
||||
position: relative;
|
||||
flex-shrink: 0;
|
||||
}
|
||||
|
||||
.outline-sidebar {
|
||||
@media (min-width: map-get($grid-breakpoints, "xl")) {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 0;
|
||||
}
|
||||
|
||||
@@ -68,6 +68,7 @@ export const useCourseOutlineSidebar = () => {
|
||||
} else {
|
||||
toggleSidebar(ID);
|
||||
window.sessionStorage.removeItem('hideCourseOutlineSidebar');
|
||||
window.sessionStorage.setItem(`notificationTrayStatus.${courseId}`, 'closed');
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import React, { useEffect, useState } from 'react';
|
||||
import { useEffect, useState } from 'react';
|
||||
import { getConfig } from '@edx/frontend-platform';
|
||||
import PropTypes from 'prop-types';
|
||||
import { getNotices } from './api';
|
||||
@@ -25,11 +25,7 @@ const NoticesProvider = ({ children }) => {
|
||||
getData();
|
||||
}, []);
|
||||
|
||||
return (
|
||||
<div>
|
||||
{isRedirected === true ? null : children}
|
||||
</div>
|
||||
);
|
||||
return isRedirected === true ? null : children;
|
||||
};
|
||||
|
||||
NoticesProvider.propTypes = {
|
||||
|
||||
168
src/index.jsx
168
src/index.jsx
@@ -49,100 +49,102 @@ subscribe(APP_READY, () => {
|
||||
<PathFixesProvider>
|
||||
<NoticesProvider>
|
||||
<UserMessagesProvider>
|
||||
<Routes>
|
||||
<Route path="*" element={<PageWrap><PageNotFound /></PageWrap>} />
|
||||
<Route path={ROUTES.UNSUBSCRIBE} element={<PageWrap><GoalUnsubscribe /></PageWrap>} />
|
||||
<Route path={ROUTES.REDIRECT} element={<PageWrap><CoursewareRedirectLandingPage /></PageWrap>} />
|
||||
<Route
|
||||
path={ROUTES.PREFERENCES_UNSUBSCRIBE}
|
||||
element={
|
||||
<PageWrap><PreferencesUnsubscribe /></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>
|
||||
</DecodePageRoute>
|
||||
)}
|
||||
/>
|
||||
<Route
|
||||
path={DECODE_ROUTES.LIVE}
|
||||
element={(
|
||||
<DecodePageRoute>
|
||||
<TabContainer tab="lti_live" fetch={fetchLiveTab} slice="courseHome">
|
||||
<LiveTab />
|
||||
</TabContainer>
|
||||
</DecodePageRoute>
|
||||
)}
|
||||
/>
|
||||
<Route
|
||||
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>
|
||||
</DecodePageRoute>
|
||||
)}
|
||||
/>
|
||||
{DECODE_ROUTES.PROGRESS.map((route) => (
|
||||
<div className="app-container">
|
||||
<Routes>
|
||||
<Route path="*" element={<PageWrap><PageNotFound /></PageWrap>} />
|
||||
<Route path={ROUTES.UNSUBSCRIBE} element={<PageWrap><GoalUnsubscribe /></PageWrap>} />
|
||||
<Route path={ROUTES.REDIRECT} element={<PageWrap><CoursewareRedirectLandingPage /></PageWrap>} />
|
||||
<Route
|
||||
key={route}
|
||||
path={route}
|
||||
path={ROUTES.PREFERENCES_UNSUBSCRIBE}
|
||||
element={
|
||||
<PageWrap><PreferencesUnsubscribe /></PageWrap>
|
||||
}
|
||||
/>
|
||||
<Route
|
||||
path={DECODE_ROUTES.ACCESS_DENIED}
|
||||
element={<DecodePageRoute><CourseAccessErrorPage /></DecodePageRoute>}
|
||||
/>
|
||||
<Route
|
||||
path={DECODE_ROUTES.HOME}
|
||||
element={(
|
||||
<DecodePageRoute>
|
||||
<TabContainer
|
||||
tab="progress"
|
||||
fetch={fetchProgressTab}
|
||||
slice="courseHome"
|
||||
isProgressTab
|
||||
>
|
||||
<ProgressTab />
|
||||
<TabContainer tab="outline" fetch={fetchOutlineTab} slice="courseHome">
|
||||
<OutlineTab />
|
||||
</TabContainer>
|
||||
</DecodePageRoute>
|
||||
)}
|
||||
)}
|
||||
/>
|
||||
))}
|
||||
<Route
|
||||
path={DECODE_ROUTES.COURSE_END}
|
||||
element={(
|
||||
<DecodePageRoute>
|
||||
<TabContainer tab="courseware" fetch={fetchCourse} slice="courseware">
|
||||
<CourseExit />
|
||||
</TabContainer>
|
||||
</DecodePageRoute>
|
||||
)}
|
||||
/>
|
||||
{DECODE_ROUTES.COURSEWARE.map((route) => (
|
||||
<Route
|
||||
key={route}
|
||||
path={route}
|
||||
path={DECODE_ROUTES.LIVE}
|
||||
element={(
|
||||
<DecodePageRoute>
|
||||
<CoursewareContainer />
|
||||
<TabContainer tab="lti_live" fetch={fetchLiveTab} slice="courseHome">
|
||||
<LiveTab />
|
||||
</TabContainer>
|
||||
</DecodePageRoute>
|
||||
)}
|
||||
)}
|
||||
/>
|
||||
))}
|
||||
</Routes>
|
||||
<Route
|
||||
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>
|
||||
</DecodePageRoute>
|
||||
)}
|
||||
/>
|
||||
{DECODE_ROUTES.PROGRESS.map((route) => (
|
||||
<Route
|
||||
key={route}
|
||||
path={route}
|
||||
element={(
|
||||
<DecodePageRoute>
|
||||
<TabContainer
|
||||
tab="progress"
|
||||
fetch={fetchProgressTab}
|
||||
slice="courseHome"
|
||||
isProgressTab
|
||||
>
|
||||
<ProgressTab />
|
||||
</TabContainer>
|
||||
</DecodePageRoute>
|
||||
)}
|
||||
/>
|
||||
))}
|
||||
<Route
|
||||
path={DECODE_ROUTES.COURSE_END}
|
||||
element={(
|
||||
<DecodePageRoute>
|
||||
<TabContainer tab="courseware" fetch={fetchCourse} slice="courseware">
|
||||
<CourseExit />
|
||||
</TabContainer>
|
||||
</DecodePageRoute>
|
||||
)}
|
||||
/>
|
||||
{DECODE_ROUTES.COURSEWARE.map((route) => (
|
||||
<Route
|
||||
key={route}
|
||||
path={route}
|
||||
element={(
|
||||
<DecodePageRoute>
|
||||
<CoursewareContainer />
|
||||
</DecodePageRoute>
|
||||
)}
|
||||
/>
|
||||
))}
|
||||
</Routes>
|
||||
</div>
|
||||
</UserMessagesProvider>
|
||||
</NoticesProvider>
|
||||
</PathFixesProvider>
|
||||
|
||||
@@ -8,13 +8,20 @@
|
||||
|
||||
|
||||
#root {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-height: 100vh;
|
||||
|
||||
.app-container {
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
min-height: 100svh;
|
||||
}
|
||||
|
||||
main {
|
||||
flex-grow: 1;
|
||||
}
|
||||
#main-content {
|
||||
flex-grow: 1;
|
||||
display: flex;
|
||||
flex-direction: column;
|
||||
}
|
||||
|
||||
header {
|
||||
flex: 0 0 auto;
|
||||
|
||||
Reference in New Issue
Block a user