diff --git a/src/course-home/data/__factories__/outlineTabData.factory.js b/src/course-home/data/__factories__/outlineTabData.factory.js
index 6cc4faf0..b3faf6df 100644
--- a/src/course-home/data/__factories__/outlineTabData.factory.js
+++ b/src/course-home/data/__factories__/outlineTabData.factory.js
@@ -25,7 +25,16 @@ Factory.define('outlineTabData')
has_visited_course: false,
url: `${host}/courses/${courseId}/jump_to/block-v1:edX+Test+Block@12345abcde`,
}))
+ .attr('verified_mode', ['host'], (host) => ({
+ access_expiration_date: '2050-01-01T12:00:00',
+ currency: 'USD',
+ currency_symbol: '$',
+ price: 149,
+ sku: 'ABCD1234',
+ upgrade_url: `${host}/dashboard`,
+ }))
.attrs({
+ can_show_upgrade_sock: true,
course_expired_html: null,
course_goals: {
goal_options: [],
diff --git a/src/course-home/data/__snapshots__/redux.test.js.snap b/src/course-home/data/__snapshots__/redux.test.js.snap
index 9aec5144..5ea68ed0 100644
--- a/src/course-home/data/__snapshots__/redux.test.js.snap
+++ b/src/course-home/data/__snapshots__/redux.test.js.snap
@@ -339,6 +339,7 @@ Object {
},
"outline": Object {
"course-v1:edX+DemoX+Demo_Course_1": Object {
+ "canShowUpgradeSock": true,
"courseBlocks": Object {
"courses": Object {
"block-v1:edX+DemoX+Demo_Course+type@course+block@bcdabcdabcdabcdabcdabcdabcdabcd3": Object {
@@ -407,6 +408,14 @@ Object {
"hasVisitedCourse": false,
"url": "http://localhost:18000/courses/course-v1:edX+DemoX+Demo_Course/jump_to/block-v1:edX+Test+Block@12345abcde",
},
+ "verifiedMode": Object {
+ "accessExpirationDate": "2050-01-01T12:00:00",
+ "currency": "USD",
+ "currencySymbol": "$",
+ "price": 149,
+ "sku": "ABCD1234",
+ "upgradeUrl": "http://localhost:18000/dashboard",
+ },
"welcomeMessageHtml": "
Welcome to this course!
",
},
},
diff --git a/src/course-home/data/api.js b/src/course-home/data/api.js
index 9e47a6f6..c22bce0d 100644
--- a/src/course-home/data/api.js
+++ b/src/course-home/data/api.js
@@ -141,6 +141,7 @@ export async function getOutlineTabData(courseId) {
const {
data,
} = tabData;
+ const canShowUpgradeSock = data.can_show_upgrade_sock;
const courseBlocks = data.course_blocks ? normalizeOutlineBlocks(courseId, data.course_blocks.blocks) : {};
const courseGoals = camelCaseObject(data.course_goals);
const courseExpiredHtml = data.course_expired_html;
@@ -152,9 +153,11 @@ export async function getOutlineTabData(courseId) {
const hasEnded = data.has_ended;
const offerHtml = data.offer_html;
const resumeCourse = camelCaseObject(data.resume_course);
+ const verifiedMode = camelCaseObject(data.verified_mode);
const welcomeMessageHtml = data.welcome_message_html;
return {
+ canShowUpgradeSock,
courseBlocks,
courseGoals,
courseExpiredHtml,
@@ -166,6 +169,7 @@ export async function getOutlineTabData(courseId) {
hasEnded,
offerHtml,
resumeCourse,
+ verifiedMode,
welcomeMessageHtml,
};
}
diff --git a/src/course-home/outline-tab/OutlineTab.jsx b/src/course-home/outline-tab/OutlineTab.jsx
index 19f46515..5fc4a95e 100644
--- a/src/course-home/outline-tab/OutlineTab.jsx
+++ b/src/course-home/outline-tab/OutlineTab.jsx
@@ -1,4 +1,4 @@
-import React, { useState } from 'react';
+import React, { useRef, useState } from 'react';
import { useSelector } from 'react-redux';
import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
@@ -8,6 +8,7 @@ import { AlertList } from '../../generic/user-messages';
import CourseDates from './widgets/CourseDates';
import CourseGoalCard from './widgets/CourseGoalCard';
import CourseHandouts from './widgets/CourseHandouts';
+import CourseSock from '../../generic/course-sock';
import CourseTools from './widgets/CourseTools';
import DatesBannerContainer from '../dates-banner/DatesBannerContainer';
import { fetchOutlineTab } from '../data';
@@ -15,6 +16,7 @@ import genericMessages from '../../generic/messages';
import messages from './messages';
import Section from './Section';
import UpdateGoalSelector from './widgets/UpdateGoalSelector';
+import UpgradeCard from './widgets/UpgradeCard';
import useAccessExpirationAlert from '../../alerts/access-expiration-alert';
import useCertificateAvailableAlert from './alerts/certificate-available-alert';
import useCourseEndAlert from './alerts/course-end-alert';
@@ -41,6 +43,7 @@ function OutlineTab({ intl }) {
} = useModel('courses', courseId);
const {
+ canShowUpgradeSock,
courseBlocks: {
courses,
sections,
@@ -60,6 +63,7 @@ function OutlineTab({ intl }) {
url: resumeCourseUrl,
},
offerHtml,
+ verifiedMode,
} = useModel('outline', courseId);
const [courseGoalToDisplay, setCourseGoalToDisplay] = useState(selectedGoal);
@@ -79,6 +83,8 @@ function OutlineTab({ intl }) {
const rootCourseId = courses && Object.keys(courses)[0];
+ const courseSock = useRef(null);
+
return (
<>
+ { courseSock.current.showToUser(); } : null}
+ />
+ {canShowUpgradeSock && }
>
);
}
diff --git a/src/course-home/outline-tab/messages.js b/src/course-home/outline-tab/messages.js
index fc10d2fe..f9036f47 100644
--- a/src/course-home/outline-tab/messages.js
+++ b/src/course-home/outline-tab/messages.js
@@ -62,6 +62,10 @@ const messages = defineMessages({
defaultMessage: 'Incomplete section',
description: 'Text used to describe the gray checkmark icon in front of a section title',
},
+ learnMore: {
+ id: 'learning.outline.learnMore',
+ defaultMessage: 'Learn More',
+ },
openSection: {
id: 'learning.outline.altText.openSection',
defaultMessage: 'Open',
@@ -83,6 +87,19 @@ const messages = defineMessages({
id: 'learning.outline.tools',
defaultMessage: 'Course Tools',
},
+ upgradeButton: {
+ id: 'learning.outline.upgradeButton',
+ defaultMessage: 'Upgrade ({symbol}{price})',
+ },
+ upgradeTitle: {
+ id: 'learning.outline.upgradeTitle',
+ defaultMessage: 'Pursue a verified certificate',
+ },
+ certAlt: {
+ id: 'learning.outline.certificateAlt',
+ defaultMessage: 'Example Certificate',
+ description: 'Alternate text displayed when the example certificate image cannot be displayed.',
+ },
welcomeMessage: {
id: 'learning.outline.welcomeMessage',
defaultMessage: 'Welcome Message',
diff --git a/src/course-home/outline-tab/widgets/CourseDates.jsx b/src/course-home/outline-tab/widgets/CourseDates.jsx
index d8dbb258..4db2ecba 100644
--- a/src/course-home/outline-tab/widgets/CourseDates.jsx
+++ b/src/course-home/outline-tab/widgets/CourseDates.jsx
@@ -17,7 +17,7 @@ function CourseDates({ courseId, intl }) {
} = useModel('outline', courseId);
return (
-
+
{intl.formatMessage(messages.dates)}
{courseDateBlocks.map((courseDateBlock) => (
+
{intl.formatMessage(messages.handouts)}
+
{intl.formatMessage(messages.tools)}
{courseTools.map((courseTool) => (
diff --git a/src/course-home/outline-tab/widgets/UpdateGoalSelector.jsx b/src/course-home/outline-tab/widgets/UpdateGoalSelector.jsx
index 5134d718..440ed21a 100644
--- a/src/course-home/outline-tab/widgets/UpdateGoalSelector.jsx
+++ b/src/course-home/outline-tab/widgets/UpdateGoalSelector.jsx
@@ -36,7 +36,7 @@ function UpdateGoalSelector({
return (
<>
-
+