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 ( <> -
+