Merge PR #50 banner/lock-access

* Commits:
  Add audit access locked banner
This commit is contained in:
stvn
2020-04-21 12:48:56 -07:00
7 changed files with 128 additions and 3 deletions

View File

@@ -150,6 +150,7 @@ function Sequence({
)}
{!gated && unitId !== null && (
<Unit
courseId={courseId}
key={unitId}
id={unitId}
onLoaded={handleUnitLoaded}

View File

@@ -1,12 +1,24 @@
import React, { useRef, useEffect, useState } from 'react';
import React, {
Suspense,
useRef,
useEffect,
useState,
} from 'react';
import PropTypes from 'prop-types';
import { getConfig } from '@edx/frontend-platform';
import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
import messages from './messages';
import BookmarkButton from '../bookmark/BookmarkButton';
import { useModel } from '../../../model-store';
import PageLoading from '../../../PageLoading';
export default function Unit({
const LockPaywall = React.lazy(() => import('./lock-paywall'));
function Unit({
courseId,
onLoaded,
id,
intl,
}) {
const iframeRef = useRef(null);
const iframeUrl = `${getConfig().LMS_BASE_URL}/xblock/${id}?show_title=0&show_bookmark_button=0`;
@@ -15,6 +27,11 @@ export default function Unit({
const [hasLoaded, setHasLoaded] = useState(false);
const unit = useModel('units', id);
const course = useModel('courses', courseId);
const {
contentTypeGatingEnabled,
enrollmentMode,
} = course;
useEffect(() => {
global.onmessage = (event) => {
@@ -40,6 +57,19 @@ export default function Unit({
isBookmarked={unit.bookmarked}
isProcessing={unit.bookmarkedUpdateState === 'loading'}
/>
{ contentTypeGatingEnabled && unit.graded && enrollmentMode === 'audit' && (
<Suspense
fallback={(
<PageLoading
srMessage={intl.formatMessage(messages['learn.loading.content.lock'])}
/>
)}
>
<LockPaywall
courseId={courseId}
/>
</Suspense>
)}
<div className="unit-iframe-wrapper">
<iframe
id="unit-iframe"
@@ -57,10 +87,14 @@ export default function Unit({
}
Unit.propTypes = {
courseId: PropTypes.string.isRequired,
id: PropTypes.string.isRequired,
intl: intlShape.isRequired,
onLoaded: PropTypes.func,
};
Unit.defaultProps = {
onLoaded: undefined,
};
export default injectIntl(Unit);

View File

@@ -0,0 +1,61 @@
import React from 'react';
import PropTypes from 'prop-types';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { faLock } from '@fortawesome/free-solid-svg-icons';
import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
import messages from './messages';
import VerifiedCert from './assets/edx-verified-mini-cert.png';
import { useModel } from '../../../../model-store';
function LockPaywall({
intl,
courseId,
}) {
const course = useModel('courses', courseId);
const {
verifiedMode,
} = course;
if (!verifiedMode) {
return null;
}
const {
currencySymbol,
price,
upgradeUrl,
} = verifiedMode;
return (
<div className="border border-gray rounded d-flex justify-content-between mt-2 p-3">
<div>
<h4 className="font-weight-bold mb-2">
<FontAwesomeIcon icon={faLock} className="text-black mr-2 ml-1" style={{ fontSize: '2rem' }} />
<span>{intl.formatMessage(messages['learn.lockPaywall.title'])}</span>
</h4>
<p className="mb-0">
<span>{intl.formatMessage(messages['learn.lockPaywall.content'])}</span>
&nbsp;
<a href={upgradeUrl}>
{intl.formatMessage(messages['learn.lockPaywall.upgrade.link'], {
currencySymbol,
price,
})}
</a>
</p>
</div>
<div>
<img
alt={intl.formatMessage(messages['learn.lockPaywall.example.alt'])}
src={VerifiedCert}
className="border-0"
style={{ height: '70px' }}
/>
</div>
</div>
);
}
LockPaywall.propTypes = {
intl: intlShape.isRequired,
courseId: PropTypes.string.isRequired,
};
export default injectIntl(LockPaywall);

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.9 KiB

View File

@@ -0,0 +1 @@
export { default } from './LockPaywall';

View File

@@ -0,0 +1,26 @@
import { defineMessages } from '@edx/frontend-platform/i18n';
const messages = defineMessages({
'learn.lockPaywall.title': {
id: 'learn.lockPaywall.title',
defaultMessage: 'Verified Track Access',
description: 'Heading for message shown to indicate that a piece of content is unavailable to audit track users.',
},
'learn.lockPaywall.content': {
id: 'learn.lockPaywall.content',
defaultMessage: 'Graded assessments are available to Verified Track learners.',
description: 'Message shown to indicate that a piece of content is unavailable to audit track users.',
},
'learn.lockPaywall.upgrade.link': {
id: 'learn.lockPaywall.upgrade.link',
defaultMessage: 'Upgrade to unlock ({currencySymbol}{price})',
description: 'A link users can click that navigates their browser to the upgrade payment page.',
},
'learn.lockPaywall.example.alt': {
id: 'learn.lockPaywall.example.alt',
defaultMessage: 'Example Certificate',
description: 'Alternate text displayed when the example certificate image cannot be displayed.',
},
});
export default messages;

View File

@@ -5,6 +5,7 @@ import { logError } from '@edx/frontend-platform/logging';
function normalizeMetadata(metadata) {
return {
contentTypeGatingEnabled: metadata.content_type_gating_enabled,
// TODO: TNL-7185: return course expired _date_, instead of _message_
courseExpiredMessage: metadata.course_expired_message,
id: metadata.id,
@@ -66,6 +67,7 @@ function normalizeBlocks(courseId, blocks) {
break;
case 'vertical':
models.units[block.id] = {
graded: block.graded,
id: block.id,
title: block.display_name,
lmsWebUrl: block.lms_web_url,
@@ -112,7 +114,7 @@ export async function getCourseBlocks(courseId) {
url.searchParams.append('course_id', courseId);
url.searchParams.append('username', username);
url.searchParams.append('depth', 3);
url.searchParams.append('requested_fields', 'children,show_gated_sections');
url.searchParams.append('requested_fields', 'children,show_gated_sections,graded');
const { data } = await getAuthenticatedHttpClient().get(url.href, {});
return normalizeBlocks(courseId, data.blocks);