diff --git a/src/alerts/enrollment-alert/EnrollmentAlert.jsx b/src/alerts/enrollment-alert/EnrollmentAlert.jsx
index b51dc6ff..c9ac6e01 100644
--- a/src/alerts/enrollment-alert/EnrollmentAlert.jsx
+++ b/src/alerts/enrollment-alert/EnrollmentAlert.jsx
@@ -5,24 +5,44 @@ import { Button } from '@edx/paragon';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
import { faSpinner } from '@fortawesome/free-solid-svg-icons';
-import { Alert } from '../../generic/user-messages';
+import { Alert, ALERT_TYPES } from '../../generic/user-messages';
import messages from './messages';
import { useEnrollClickHandler } from './hooks';
-function EnrollmentAlert({ intl, courseId }) {
+function EnrollmentAlert({ intl, payload }) {
+ const {
+ canEnroll,
+ courseId,
+ extraText,
+ isStaff,
+ } = payload;
+
const { enrollClickHandler, loading } = useEnrollClickHandler(
courseId,
- intl.formatMessage(messages['learning.enrollment.success']),
+ intl.formatMessage(messages.success),
+ );
+
+ let text = intl.formatMessage(messages.alert);
+ let type = ALERT_TYPES.ERROR;
+ if (isStaff) {
+ text = intl.formatMessage(messages.staffAlert);
+ type = ALERT_TYPES.INFO;
+ } else if (extraText) {
+ text = `${text} ${extraText}`;
+ }
+
+ const button = canEnroll && (
+
);
return (
-
- {intl.formatMessage(messages['learning.enrollment.alert'])}
+
+ {text}
{' '}
-
+ {button}
{' '}
{loading && }
@@ -31,7 +51,12 @@ function EnrollmentAlert({ intl, courseId }) {
EnrollmentAlert.propTypes = {
intl: intlShape.isRequired,
- courseId: PropTypes.string.isRequired,
+ payload: PropTypes.shape({
+ canEnroll: PropTypes.bool,
+ courseId: PropTypes.string,
+ extraText: PropTypes.string,
+ isStaff: PropTypes.bool,
+ }).isRequired,
};
export default injectIntl(EnrollmentAlert);
diff --git a/src/alerts/enrollment-alert/StaffEnrollmentAlert.jsx b/src/alerts/enrollment-alert/StaffEnrollmentAlert.jsx
deleted file mode 100644
index 229224b4..00000000
--- a/src/alerts/enrollment-alert/StaffEnrollmentAlert.jsx
+++ /dev/null
@@ -1,37 +0,0 @@
-import React from 'react';
-import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
-import PropTypes from 'prop-types';
-import { Button } from '@edx/paragon';
-
-import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-import { faSpinner } from '@fortawesome/free-solid-svg-icons';
-import { Alert } from '../../generic/user-messages';
-
-import messages from './messages';
-import { useEnrollClickHandler } from './hooks';
-
-function StaffEnrollmentAlert({ intl, courseId }) {
- const { enrollClickHandler, loading } = useEnrollClickHandler(
- courseId,
- intl.formatMessage(messages['learning.enrollment.success']),
- );
-
- return (
-
- {intl.formatMessage(messages['learning.staff.enrollment.alert'])}
- {' '}
-
- {' '}
- {loading && }
-
- );
-}
-
-StaffEnrollmentAlert.propTypes = {
- intl: intlShape.isRequired,
- courseId: PropTypes.string.isRequired,
-};
-
-export default injectIntl(StaffEnrollmentAlert);
diff --git a/src/alerts/enrollment-alert/hooks.js b/src/alerts/enrollment-alert/hooks.js
index 58db7c35..ccc23066 100644
--- a/src/alerts/enrollment-alert/hooks.js
+++ b/src/alerts/enrollment-alert/hooks.js
@@ -1,20 +1,32 @@
/* eslint-disable import/prefer-default-export */
-import {
+import React, {
useContext, useState, useCallback,
} from 'react';
+
import { UserMessagesContext, ALERT_TYPES, useAlert } from '../../generic/user-messages';
import { useModel } from '../../generic/model-store';
+
import { postCourseEnrollment } from './data/api';
+const EnrollmentAlert = React.lazy(() => import('./EnrollmentAlert'));
+
export function useEnrollmentAlert(courseId) {
const course = useModel('courses', courseId);
- const code = course.isStaff ? 'clientStaffEnrollmentAlert' : 'clientEnrollmentAlert';
+ const outline = useModel('outline', courseId);
const isVisible = course && course.isEnrolled !== undefined && !course.isEnrolled;
useAlert(isVisible, {
- code,
- topic: 'course',
+ code: 'clientEnrollmentAlert',
+ payload: {
+ canEnroll: outline.enrollAlert.canEnroll,
+ courseId,
+ extraText: outline.enrollAlert.extraText,
+ isStaff: course.isStaff,
+ },
+ topic: 'outline',
});
+
+ return EnrollmentAlert;
}
export function useEnrollClickHandler(courseId, successText) {
diff --git a/src/alerts/enrollment-alert/index.js b/src/alerts/enrollment-alert/index.js
index 72585cdb..d7edefdc 100644
--- a/src/alerts/enrollment-alert/index.js
+++ b/src/alerts/enrollment-alert/index.js
@@ -1,3 +1 @@
-export { default as EnrollmentAlert } from './EnrollmentAlert';
-export { default as StaffEnrollmentAlert } from './StaffEnrollmentAlert';
-export { useEnrollmentAlert } from './hooks';
+export { useEnrollmentAlert as default } from './hooks';
diff --git a/src/alerts/enrollment-alert/messages.js b/src/alerts/enrollment-alert/messages.js
index 659d6841..1d74456b 100644
--- a/src/alerts/enrollment-alert/messages.js
+++ b/src/alerts/enrollment-alert/messages.js
@@ -1,22 +1,22 @@
import { defineMessages } from '@edx/frontend-platform/i18n';
const messages = defineMessages({
- 'learning.enrollment.alert': {
+ alert: {
id: 'learning.enrollment.alert',
defaultMessage: 'You must be enrolled in the course to see course content.',
description: 'Message shown to indicate that a user needs to enroll in a course prior to viewing the course content. Shown as part of an alert, along with a link to enroll.',
},
- 'learning.staff.enrollment.alert': {
+ staffAlert: {
id: 'learning.staff.enrollment.alert',
defaultMessage: 'You are viewing this course as staff, and are not enrolled.',
description: 'Message shown to indicate that a user is not enrolled, but is able to view a course anyway because they are staff. Shown as part of an alert, along with a link to enroll.',
},
- 'learning.enrollment.enroll.now': {
+ enroll: {
id: 'learning.enrollment.enroll.now',
defaultMessage: 'Enroll Now',
description: 'A link prompting the user to click on it to enroll in the currently viewed course.',
},
- 'learning.enrollment.success': {
+ success: {
id: 'learning.enrollment.success',
defaultMessage: "You've successfully enrolled in this course!",
description: 'A message telling the user that their course enrollment was successful.',
diff --git a/src/alerts/logistration-alert/LogistrationAlert.jsx b/src/alerts/logistration-alert/LogistrationAlert.jsx
index 579d7d0a..304a8c55 100644
--- a/src/alerts/logistration-alert/LogistrationAlert.jsx
+++ b/src/alerts/logistration-alert/LogistrationAlert.jsx
@@ -9,7 +9,7 @@ import messages from './messages';
function LogistrationAlert({ intl }) {
const signIn = (
- {intl.formatMessage(messages['learning.logistration.login'])}
+ {intl.formatMessage(messages.login)}
);
@@ -17,7 +17,7 @@ function LogistrationAlert({ intl }) {
// This is complicated by the fact that we don't have a REGISTER_URL env variable available.
const register = (
- {intl.formatMessage(messages['learning.logistration.register'])}
+ {intl.formatMessage(messages.register)}
);
diff --git a/src/alerts/logistration-alert/hooks.js b/src/alerts/logistration-alert/hooks.js
index 3d7981f3..a2370a48 100644
--- a/src/alerts/logistration-alert/hooks.js
+++ b/src/alerts/logistration-alert/hooks.js
@@ -9,7 +9,7 @@ export function useLogistrationAlert() {
useAlert(isVisible, {
code: 'clientLogistrationAlert',
- topic: 'course',
+ topic: 'outline',
dismissible: false,
type: ALERT_TYPES.ERROR,
});
diff --git a/src/alerts/logistration-alert/messages.js b/src/alerts/logistration-alert/messages.js
index b30e713b..35ae74d4 100644
--- a/src/alerts/logistration-alert/messages.js
+++ b/src/alerts/logistration-alert/messages.js
@@ -1,12 +1,12 @@
import { defineMessages } from '@edx/frontend-platform/i18n';
const messages = defineMessages({
- 'learning.logistration.login': {
+ login: {
id: 'learning.logistration.login',
defaultMessage: 'sign in',
description: 'Text in a link, prompting the user to log in. Used in "learning.logistration.alert"',
},
- 'learning.logistration.register': {
+ register: {
id: 'learning.logistration.register',
defaultMessage: 'register',
description: 'Text in a link, prompting the user to create an account. Used in "learning.logistration.alert"',
diff --git a/src/course-home/data/__factories__/outlineTabData.factory.js b/src/course-home/data/__factories__/outlineTabData.factory.js
index 9d84f684..92033eac 100644
--- a/src/course-home/data/__factories__/outlineTabData.factory.js
+++ b/src/course-home/data/__factories__/outlineTabData.factory.js
@@ -16,4 +16,8 @@ Factory.define('outlineTabData')
blocks: courseBlocks.blocks,
};
})
+ .attr('enroll_alert', {
+ can_enroll: true,
+ extra_text: 'Contact the administrator.',
+ })
.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 b0baead2..465bf405 100644
--- a/src/course-home/data/__snapshots__/redux.test.js.snap
+++ b/src/course-home/data/__snapshots__/redux.test.js.snap
@@ -197,6 +197,10 @@ Object {
"url": "http://localhost:18000/courses/course-v1:edX+DemoX+Demo_Course/bookmarks/",
},
"datesWidget": undefined,
+ "enrollAlert": Object {
+ "canEnroll": true,
+ "extraText": "Contact the administrator.",
+ },
"handoutsHtml": "",
"id": "course-v1:edX+DemoX+Demo_Course_1",
"welcomeMessageHtml": undefined,
diff --git a/src/course-home/data/api.js b/src/course-home/data/api.js
index 36707733..0132915b 100644
--- a/src/course-home/data/api.js
+++ b/src/course-home/data/api.js
@@ -71,6 +71,7 @@ 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 enrollAlert = camelCaseObject(data.enroll_alert);
const handoutsHtml = data.handouts_html;
const welcomeMessageHtml = data.welcome_message_html;
@@ -78,6 +79,7 @@ export async function getOutlineTabData(courseId) {
courseTools,
courseBlocks,
datesWidget,
+ enrollAlert,
handoutsHtml,
welcomeMessageHtml,
};
diff --git a/src/course-home/outline-tab/OutlineTab.jsx b/src/course-home/outline-tab/OutlineTab.jsx
index 0016d107..d171e956 100644
--- a/src/course-home/outline-tab/OutlineTab.jsx
+++ b/src/course-home/outline-tab/OutlineTab.jsx
@@ -10,14 +10,11 @@ import CourseHandouts from './widgets/CourseHandouts';
import CourseTools from './widgets/CourseTools';
import messages from './messages';
import Section from './Section';
+import useEnrollmentAlert from '../../alerts/enrollment-alert';
+import { useLogistrationAlert } from '../../alerts/logistration-alert';
import { useModel } from '../../generic/model-store';
import WelcomeMessage from './widgets/WelcomeMessage';
-// Note that we import from the component files themselves in the enrollment-alert package.
-// This is because React.lazy() requires that we import() from a file with a Component as its
-// default export.
-// See React.lazy docs here: https://reactjs.org/docs/code-splitting.html#reactlazy
-const { EnrollmentAlert, StaffEnrollmentAlert } = React.lazy(() => import('../../alerts/enrollment-alert'));
const LogistrationAlert = React.lazy(() => import('../../alerts/logistration-alert'));
function OutlineTab({ intl }) {
@@ -42,6 +39,9 @@ function OutlineTab({ intl }) {
},
} = useModel('outline', courseId);
+ const clientEnrollmentAlert = useEnrollmentAlert(courseId);
+ useLogistrationAlert();
+
const rootCourseId = Object.keys(courses)[0];
const { sectionIds } = courses[rootCourseId];
@@ -51,8 +51,7 @@ function OutlineTab({ intl }) {
topic="outline"
className="mb-3"
customAlerts={{
- clientEnrollmentAlert: EnrollmentAlert,
- clientStaffEnrollmentAlert: StaffEnrollmentAlert,
+ clientEnrollmentAlert,
clientLogistrationAlert: LogistrationAlert,
}}
/>
diff --git a/src/courseware/course/Course.jsx b/src/courseware/course/Course.jsx
index 217cdc72..640017d0 100644
--- a/src/courseware/course/Course.jsx
+++ b/src/courseware/course/Course.jsx
@@ -21,9 +21,6 @@ import { useModel } from '../../generic/model-store';
// default export.
// See React.lazy docs here: https://reactjs.org/docs/code-splitting.html#reactlazy
const AccessExpirationAlert = React.lazy(() => import('../../alerts/access-expiration-alert/AccessExpirationAlert'));
-const EnrollmentAlert = React.lazy(() => import('../../alerts/enrollment-alert/EnrollmentAlert'));
-const StaffEnrollmentAlert = React.lazy(() => import('../../alerts/enrollment-alert/StaffEnrollmentAlert'));
-const LogistrationAlert = React.lazy(() => import('../../alerts/logistration-alert'));
const OfferAlert = React.lazy(() => import('../../alerts/offer-alert/OfferAlert'));
function Course({
@@ -66,16 +63,9 @@ function Course({
className="my-3"
topic="course"
customAlerts={{
- clientEnrollmentAlert: EnrollmentAlert,
- clientStaffEnrollmentAlert: StaffEnrollmentAlert,
- clientLogistrationAlert: LogistrationAlert,
clientAccessExpirationAlert: AccessExpirationAlert,
clientOfferAlert: OfferAlert,
}}
- // courseId is provided because EnrollmentAlert and StaffEnrollmentAlert require it.
- customProps={{
- courseId,
- }}
/>