diff --git a/src/course-home/data/__factories__/outlineTabData.factory.js b/src/course-home/data/__factories__/outlineTabData.factory.js
index 10c73219..c9f5d39b 100644
--- a/src/course-home/data/__factories__/outlineTabData.factory.js
+++ b/src/course-home/data/__factories__/outlineTabData.factory.js
@@ -12,4 +12,5 @@ Factory.define('outlineTabData')
}))
.attr('course_blocks', ['courseId'], courseId => ({
blocks: Factory.build('courseBlocks', { courseId }).blocks,
- }));
+ }))
+ .attr('handouts_html', [], () => '
');
diff --git a/src/course-home/data/__snapshots__/redux.test.js.snap b/src/course-home/data/__snapshots__/redux.test.js.snap
index 8473c1c3..39a0878a 100644
--- a/src/course-home/data/__snapshots__/redux.test.js.snap
+++ b/src/course-home/data/__snapshots__/redux.test.js.snap
@@ -196,6 +196,7 @@ Object {
"url": "http://localhost:18000/courses/course-v1:edX+DemoX+Demo_Course/bookmarks/",
},
"datesWidget": undefined,
+ "handoutsHtml": "",
"id": "course-v1:edX+DemoX+Demo_Course_1",
},
},
diff --git a/src/course-home/data/api.js b/src/course-home/data/api.js
index 463a4a8b..c1310535 100644
--- a/src/course-home/data/api.js
+++ b/src/course-home/data/api.js
@@ -71,8 +71,14 @@ export async function getOutlineTabData(courseId) {
const courseBlocks = normalizeBlocks(courseId, data.course_blocks.blocks);
const courseTools = camelCaseObject(data.course_tools);
const datesWidget = camelCaseObject(data.dates_widget);
+ const handoutsHtml = data.handouts_html;
- return { courseTools, courseBlocks, datesWidget };
+ return {
+ courseTools,
+ courseBlocks,
+ datesWidget,
+ handoutsHtml,
+ };
}
export async function postCourseDeadlines(courseId) {
diff --git a/src/course-home/outline-tab/LmsHtmlFragment.jsx b/src/course-home/outline-tab/LmsHtmlFragment.jsx
new file mode 100644
index 00000000..5496ce3b
--- /dev/null
+++ b/src/course-home/outline-tab/LmsHtmlFragment.jsx
@@ -0,0 +1,39 @@
+import React, { useRef } from 'react';
+import PropTypes from 'prop-types';
+
+import { getConfig } from '@edx/frontend-platform';
+
+export default function LmsHtmlFragment({ html, title, ...rest }) {
+ const wholePage = `
+
+
+
+
+
+ ${html}
+
+`;
+
+ const iframe = useRef(null);
+ function handleLoad() {
+ iframe.current.height = iframe.current.contentWindow.document.body.scrollHeight;
+ }
+
+ return (
+
+ );
+}
+
+LmsHtmlFragment.propTypes = {
+ html: PropTypes.string.isRequired,
+ title: PropTypes.string.isRequired,
+};
diff --git a/src/course-home/outline-tab/OutlineTab.jsx b/src/course-home/outline-tab/OutlineTab.jsx
index 9b8c8b18..20d03e54 100644
--- a/src/course-home/outline-tab/OutlineTab.jsx
+++ b/src/course-home/outline-tab/OutlineTab.jsx
@@ -1,11 +1,14 @@
import React from 'react';
import { useSelector } from 'react-redux';
import { Button } from '@edx/paragon';
+import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
import { AlertList } from '../../generic/user-messages';
import CourseDates from './widgets/CourseDates';
+// import CourseHandouts from './widgets/CourseHandouts';
import CourseTools from './widgets/CourseTools';
+import messages from './messages';
import Section from './Section';
import { useModel } from '../../generic/model-store';
@@ -16,7 +19,7 @@ import { useModel } from '../../generic/model-store';
const { EnrollmentAlert, StaffEnrollmentAlert } = React.lazy(() => import('../../alerts/enrollment-alert'));
const LogistrationAlert = React.lazy(() => import('../../alerts/logistration-alert'));
-export default function OutlineTab() {
+function OutlineTab({ intl }) {
const {
courseId,
} = useSelector(state => state.courseHome);
@@ -54,7 +57,7 @@ export default function OutlineTab() {
/>
{title}
- Resume Course
+ {intl.formatMessage(messages.resume)}
@@ -80,8 +83,19 @@ export default function OutlineTab() {
isEnrolled={isEnrolled}
courseId={courseId}
/>
+ {/* Disabled until we decide whether iframes are the best solution for handouts
+
+ */}
>
);
}
+
+OutlineTab.propTypes = {
+ intl: intlShape.isRequired,
+};
+
+export default injectIntl(OutlineTab);
diff --git a/src/course-home/outline-tab/messages.js b/src/course-home/outline-tab/messages.js
new file mode 100644
index 00000000..a7011adf
--- /dev/null
+++ b/src/course-home/outline-tab/messages.js
@@ -0,0 +1,26 @@
+import { defineMessages } from '@edx/frontend-platform/i18n';
+
+const messages = defineMessages({
+ allDates: {
+ id: 'learning.outline.dates.all',
+ defaultMessage: 'View all course dates',
+ },
+ dates: {
+ id: 'learning.outline.dates',
+ defaultMessage: 'Upcoming Dates',
+ },
+ handouts: {
+ id: 'learning.outline.handouts',
+ defaultMessage: 'Course Handouts',
+ },
+ resume: {
+ id: 'learning.outline.resume',
+ defaultMessage: 'Resume Course',
+ },
+ tools: {
+ id: 'learning.outline.tools',
+ defaultMessage: 'Course Tools',
+ },
+});
+
+export default messages;
diff --git a/src/course-home/outline-tab/widgets/CourseDates.jsx b/src/course-home/outline-tab/widgets/CourseDates.jsx
index 80142215..f2615ed5 100644
--- a/src/course-home/outline-tab/widgets/CourseDates.jsx
+++ b/src/course-home/outline-tab/widgets/CourseDates.jsx
@@ -1,15 +1,20 @@
import React from 'react';
import PropTypes from 'prop-types';
-import { useModel } from '../../../generic/model-store';
-import DateSummary from '../DateSummary';
-export default function CourseDates({ courseId }) {
+import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
+
+import DateSummary from '../DateSummary';
+import messages from '../messages';
+import { useModel } from '../../../generic/model-store';
+
+function CourseDates({ courseId, intl }) {
const {
datesWidget,
} = useModel('outline', courseId);
+
return (
);
}
CourseDates.propTypes = {
courseId: PropTypes.string,
+ intl: intlShape.isRequired,
};
CourseDates.defaultProps = {
courseId: null,
};
+
+export default injectIntl(CourseDates);
diff --git a/src/course-home/outline-tab/widgets/CourseHandouts.jsx b/src/course-home/outline-tab/widgets/CourseHandouts.jsx
new file mode 100644
index 00000000..5ed67b0a
--- /dev/null
+++ b/src/course-home/outline-tab/widgets/CourseHandouts.jsx
@@ -0,0 +1,35 @@
+import React from 'react';
+import PropTypes from 'prop-types';
+
+import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
+
+import LmsHtmlFragment from '../LmsHtmlFragment';
+import messages from '../messages';
+import { useModel } from '../../../generic/model-store';
+
+function CourseHandouts({ courseId, intl }) {
+ const {
+ handoutsHtml,
+ } = useModel('outline', courseId);
+
+ if (!handoutsHtml) {
+ return null;
+ }
+
+ return (
+
+ {intl.formatMessage(messages.handouts)}
+
+
+ );
+}
+
+CourseHandouts.propTypes = {
+ courseId: PropTypes.string.isRequired,
+ intl: intlShape.isRequired,
+};
+
+export default injectIntl(CourseHandouts);
diff --git a/src/course-home/outline-tab/widgets/CourseTools.jsx b/src/course-home/outline-tab/widgets/CourseTools.jsx
index 45da59b0..38ce966b 100644
--- a/src/course-home/outline-tab/widgets/CourseTools.jsx
+++ b/src/course-home/outline-tab/widgets/CourseTools.jsx
@@ -1,15 +1,17 @@
import React from 'react';
import PropTypes from 'prop-types';
+
+import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import {
faBookmark, faCertificate, faInfo, faCalendar, faStar,
} from '@fortawesome/free-solid-svg-icons';
import { faNewspaper } from '@fortawesome/free-regular-svg-icons';
+
+import messages from '../messages';
import { useModel } from '../../../generic/model-store';
-export default function CourseTools(
- { courseId },
-) {
+function CourseTools({ courseId, intl }) {
const {
courseTools,
} = useModel('outline', courseId);
@@ -35,7 +37,7 @@ export default function CourseTools(
return (
- Course Tools
+ {intl.formatMessage(messages.tools)}
{courseTools.map((courseTool) => (