diff --git a/src/course-home/data/api.js b/src/course-home/data/api.js index 0132915b..ac3a1e31 100644 --- a/src/course-home/data/api.js +++ b/src/course-home/data/api.js @@ -94,3 +94,8 @@ export async function postDismissWelcomeMessage(courseId) { const url = new URL(`${getConfig().LMS_BASE_URL}/api/course_home/v1/dismiss_welcome_message`); await getAuthenticatedHttpClient().post(url.href, { course_id: courseId }); } + +export async function postRequestCert(courseId) { + const url = new URL(`${getConfig().LMS_BASE_URL}/courses/${courseId}/generate_user_cert`); + await getAuthenticatedHttpClient().post(url.href); +} diff --git a/src/course-home/data/thunks.js b/src/course-home/data/thunks.js index 0caf530a..4b822fdd 100644 --- a/src/course-home/data/thunks.js +++ b/src/course-home/data/thunks.js @@ -6,6 +6,7 @@ import { getProgressTabData, postCourseDeadlines, postDismissWelcomeMessage, + postRequestCert, } from './api'; import { @@ -84,3 +85,7 @@ export function resetDeadlines(courseId, getTabData) { export function dismissWelcomeMessage(courseId) { return async () => postDismissWelcomeMessage(courseId); } + +export function requestCert(courseId) { + return async () => postRequestCert(courseId); +} diff --git a/src/course-home/progress-tab/CertificateBanner.jsx b/src/course-home/progress-tab/CertificateBanner.jsx new file mode 100644 index 00000000..b44d0bdb --- /dev/null +++ b/src/course-home/progress-tab/CertificateBanner.jsx @@ -0,0 +1,73 @@ +import React from 'react'; +import { useDispatch, useSelector } from 'react-redux'; + +import { injectIntl, intlShape } from '@edx/frontend-platform/i18n'; +import { requestCert } from '../data/thunks'; + +import { useModel } from '../../generic/model-store'; +import messages from './messages'; +import VerifiedCert from '../../courseware/course/sequence/lock-paywall/assets/edx-verified-mini-cert.png'; + +function CertificateBanner({ intl }) { + const { + courseId, + } = useSelector(state => state.courseHome); + + const { + certificateData, + enrollmentMode, + } = useModel('progress', courseId); + if (certificateData === null || enrollmentMode === 'audit') { return null; } + const { certUrl, certDownloadUrl } = certificateData; + const dispatch = useDispatch(); + function requestHandler() { + dispatch(requestCert(courseId)); + } + return ( + + + + {certificateData.title} + {certificateData.msg} + + {certUrl && ( + + + {intl.formatMessage(messages.viewCert)} + {intl.formatMessage(messages.opensNewWindow)} + + + )} + {!certUrl && certificateData.isDownloadable && ( + + + {intl.formatMessage(messages.downloadCert)} + {intl.formatMessage(messages.opensNewWindow)} + + + )} + {!certUrl && !certificateData.isDownloadable && certificateData.isRequestable && ( + + + {intl.formatMessage(messages.requestCert)} + + + )} + + + + + + ); +} + +CertificateBanner.propTypes = { + intl: intlShape.isRequired, +}; + +export default injectIntl(CertificateBanner); diff --git a/src/course-home/progress-tab/ProgressGraph.jsx b/src/course-home/progress-tab/ProgressGraph.jsx new file mode 100644 index 00000000..e69de29b diff --git a/src/course-home/progress-tab/ProgressTab.jsx b/src/course-home/progress-tab/ProgressTab.jsx index e9489755..78b5645e 100644 --- a/src/course-home/progress-tab/ProgressTab.jsx +++ b/src/course-home/progress-tab/ProgressTab.jsx @@ -1,24 +1,34 @@ import React from 'react'; import { useSelector } from 'react-redux'; import { getAuthenticatedUser } from '@edx/frontend-platform/auth'; +import { injectIntl, intlShape } from '@edx/frontend-platform/i18n'; import { useModel } from '../../generic/model-store'; import Chapter from './Chapter'; +import CertificateBanner from './CertificateBanner'; +import messages from './messages'; -export default function ProgressTab() { +function ProgressTab({ intl }) { const { courseId, } = useSelector(state => state.courseHome); - const { administrator, username } = getAuthenticatedUser(); + const { administrator } = getAuthenticatedUser(); const { - enrollmentMode, coursewareSummary, + studioUrl, } = useModel('progress', courseId); return ( - {enrollmentMode} {administrator} {username} + {administrator && studioUrl && ( + + + {intl.formatMessage(messages.studioLink)} + + + )} + {coursewareSummary.map((chapter) => ( ); } + +ProgressTab.propTypes = { + intl: intlShape.isRequired, +}; + +export default injectIntl(ProgressTab); diff --git a/src/course-home/progress-tab/messages.js b/src/course-home/progress-tab/messages.js index 9a81a510..5ede570a 100644 --- a/src/course-home/progress-tab/messages.js +++ b/src/course-home/progress-tab/messages.js @@ -33,6 +33,31 @@ const messages = defineMessages({ id: 'learning.progress.badge.scoreEarned', defaultMessage: '{earned} of {total} possible points', }, + viewCert: { + id: 'learning.progress.badge.viewCert', + defaultMessage: 'View Certificate', + }, + downloadCert: { + id: 'learning.progress.badge.downloadCert', + defaultMessage: 'Download Your Certificate', + }, + requestCert: { + id: 'learning.progress.badge.requestCert', + defaultMessage: 'Request Certificate', + }, + opensNewWindow: { + id: 'learning.progress.badge.opensNewWindow', + defaultMessage: 'Opens in a new browser window', + }, + certAlt: { + id: 'learning.progress.badge.certAlt', + defaultMessage: 'Example Certificate', + description: 'Alternate text displayed when the example certificate image cannot be displayed.', + }, + studioLink: { + id: 'learning.progress.badge.studioLink', + defaultMessage: 'View grading in studio', + }, }); export default messages;