AA-279: Add course expired alert to outline
It was previously only used in the courseware. But to match the LMS, we also want to show it on the outline tab.
This commit is contained in:
@@ -1,14 +1,15 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
|
|
||||||
import { Alert } from '../../generic/user-messages';
|
import { Alert, ALERT_TYPES } from '../../generic/user-messages';
|
||||||
|
|
||||||
function AccessExpirationAlert({ payload }) {
|
function AccessExpirationAlert({ payload }) {
|
||||||
const {
|
const {
|
||||||
rawHtml,
|
rawHtml,
|
||||||
} = payload;
|
} = payload;
|
||||||
return rawHtml && (
|
return rawHtml && (
|
||||||
<Alert type="info">
|
<Alert type={ALERT_TYPES.INFO}>
|
||||||
|
{/* eslint-disable-next-line react/no-danger */}
|
||||||
<div dangerouslySetInnerHTML={{ __html: rawHtml }} />
|
<div dangerouslySetInnerHTML={{ __html: rawHtml }} />
|
||||||
</Alert>
|
</Alert>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -1,18 +1,21 @@
|
|||||||
/* eslint-disable import/prefer-default-export */
|
import React, { useMemo } from 'react';
|
||||||
import { useMemo } from 'react';
|
|
||||||
import { useModel } from '../../generic/model-store';
|
|
||||||
import { useAlert } from '../../generic/user-messages';
|
import { useAlert } from '../../generic/user-messages';
|
||||||
|
|
||||||
export function useAccessExpirationAlert(courseId) {
|
const AccessExpirationAlert = React.lazy(() => import('./AccessExpirationAlert'));
|
||||||
const course = useModel('courses', courseId);
|
|
||||||
const rawHtml = (course && course.courseExpiredMessage) || null;
|
function useAccessExpirationAlert(courseExpiredMessage, topic) {
|
||||||
|
const rawHtml = courseExpiredMessage || null;
|
||||||
const isVisible = !!rawHtml; // If it exists, show it.
|
const isVisible = !!rawHtml; // If it exists, show it.
|
||||||
|
|
||||||
const payload = useMemo(() => ({ rawHtml }), [rawHtml]);
|
const payload = useMemo(() => ({ rawHtml }), [rawHtml]);
|
||||||
|
|
||||||
useAlert(isVisible, {
|
useAlert(isVisible, {
|
||||||
code: 'clientAccessExpirationAlert',
|
code: 'clientAccessExpirationAlert',
|
||||||
topic: 'course',
|
|
||||||
payload,
|
payload,
|
||||||
|
topic,
|
||||||
});
|
});
|
||||||
|
|
||||||
|
return { clientAccessExpirationAlert: AccessExpirationAlert };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export default useAccessExpirationAlert;
|
||||||
|
|||||||
@@ -1,2 +1 @@
|
|||||||
export { default as AccessExpirationAlert } from './AccessExpirationAlert';
|
export { default } from './hooks';
|
||||||
export { useAccessExpirationAlert } from './hooks';
|
|
||||||
|
|||||||
@@ -69,6 +69,7 @@ export async function getOutlineTabData(courseId) {
|
|||||||
data,
|
data,
|
||||||
} = tabData;
|
} = tabData;
|
||||||
const courseBlocks = normalizeBlocks(courseId, data.course_blocks.blocks);
|
const courseBlocks = normalizeBlocks(courseId, data.course_blocks.blocks);
|
||||||
|
const courseExpiredHtml = data.course_expired_html;
|
||||||
const courseTools = camelCaseObject(data.course_tools);
|
const courseTools = camelCaseObject(data.course_tools);
|
||||||
const datesWidget = camelCaseObject(data.dates_widget);
|
const datesWidget = camelCaseObject(data.dates_widget);
|
||||||
const enrollAlert = camelCaseObject(data.enroll_alert);
|
const enrollAlert = camelCaseObject(data.enroll_alert);
|
||||||
@@ -77,8 +78,9 @@ export async function getOutlineTabData(courseId) {
|
|||||||
const welcomeMessageHtml = data.welcome_message_html;
|
const welcomeMessageHtml = data.welcome_message_html;
|
||||||
|
|
||||||
return {
|
return {
|
||||||
courseTools,
|
|
||||||
courseBlocks,
|
courseBlocks,
|
||||||
|
courseExpiredHtml,
|
||||||
|
courseTools,
|
||||||
datesWidget,
|
datesWidget,
|
||||||
enrollAlert,
|
enrollAlert,
|
||||||
handoutsHtml,
|
handoutsHtml,
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ import CourseHandouts from './widgets/CourseHandouts';
|
|||||||
import CourseTools from './widgets/CourseTools';
|
import CourseTools from './widgets/CourseTools';
|
||||||
import messages from './messages';
|
import messages from './messages';
|
||||||
import Section from './Section';
|
import Section from './Section';
|
||||||
|
import useAccessExpirationAlert from '../../alerts/access-expiration-alert';
|
||||||
import useCertificateAvailableAlert from './alerts/certificate-available-alert';
|
import useCertificateAvailableAlert from './alerts/certificate-available-alert';
|
||||||
import useCourseEndAlert from './alerts/course-end-alert';
|
import useCourseEndAlert from './alerts/course-end-alert';
|
||||||
import useCourseStartAlert from './alerts/course-start-alert';
|
import useCourseStartAlert from './alerts/course-start-alert';
|
||||||
@@ -39,6 +40,7 @@ function OutlineTab({ intl }) {
|
|||||||
courses,
|
courses,
|
||||||
sections,
|
sections,
|
||||||
},
|
},
|
||||||
|
courseExpiredHtml,
|
||||||
offerHtml,
|
offerHtml,
|
||||||
} = useModel('outline', courseId);
|
} = useModel('outline', courseId);
|
||||||
|
|
||||||
@@ -48,6 +50,7 @@ function OutlineTab({ intl }) {
|
|||||||
|
|
||||||
// Below the course title alerts (appearing in the order listed here)
|
// Below the course title alerts (appearing in the order listed here)
|
||||||
const offerAlert = useOfferAlert(offerHtml, 'outline-course-alerts');
|
const offerAlert = useOfferAlert(offerHtml, 'outline-course-alerts');
|
||||||
|
const accessExpirationAlert = useAccessExpirationAlert(courseExpiredHtml, 'outline-course-alerts');
|
||||||
const courseStartAlert = useCourseStartAlert(courseId);
|
const courseStartAlert = useCourseStartAlert(courseId);
|
||||||
const courseEndAlert = useCourseEndAlert(courseId);
|
const courseEndAlert = useCourseEndAlert(courseId);
|
||||||
const certificateAvailableAlert = useCertificateAvailableAlert(courseId);
|
const certificateAvailableAlert = useCertificateAvailableAlert(courseId);
|
||||||
@@ -76,6 +79,7 @@ function OutlineTab({ intl }) {
|
|||||||
topic="outline-course-alerts"
|
topic="outline-course-alerts"
|
||||||
className="mb-3"
|
className="mb-3"
|
||||||
customAlerts={{
|
customAlerts={{
|
||||||
|
...accessExpirationAlert,
|
||||||
...certificateAvailableAlert,
|
...certificateAvailableAlert,
|
||||||
...courseEndAlert,
|
...courseEndAlert,
|
||||||
...courseStartAlert,
|
...courseStartAlert,
|
||||||
|
|||||||
@@ -5,7 +5,7 @@ import { useDispatch } from 'react-redux';
|
|||||||
import { getConfig } from '@edx/frontend-platform';
|
import { getConfig } from '@edx/frontend-platform';
|
||||||
|
|
||||||
import { AlertList } from '../../generic/user-messages';
|
import { AlertList } from '../../generic/user-messages';
|
||||||
import { useAccessExpirationAlert } from '../../alerts/access-expiration-alert';
|
import useAccessExpirationAlert from '../../alerts/access-expiration-alert';
|
||||||
import useOfferAlert from '../../alerts/offer-alert';
|
import useOfferAlert from '../../alerts/offer-alert';
|
||||||
|
|
||||||
import Sequence from './sequence';
|
import Sequence from './sequence';
|
||||||
@@ -16,12 +16,6 @@ import CourseSock from './course-sock';
|
|||||||
import ContentTools from './content-tools';
|
import ContentTools from './content-tools';
|
||||||
import { useModel } from '../../generic/model-store';
|
import { useModel } from '../../generic/model-store';
|
||||||
|
|
||||||
// Note that we import from the component files themselves in the enrollment-alert package.
|
|
||||||
// This is because Reacy.lazy() requires that we import() from a file with a Component as it's
|
|
||||||
// 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'));
|
|
||||||
|
|
||||||
function Course({
|
function Course({
|
||||||
courseId,
|
courseId,
|
||||||
sequenceId,
|
sequenceId,
|
||||||
@@ -43,13 +37,14 @@ function Course({
|
|||||||
const {
|
const {
|
||||||
canShowUpgradeSock,
|
canShowUpgradeSock,
|
||||||
celebrations,
|
celebrations,
|
||||||
|
courseExpiredMessage,
|
||||||
offerHtml,
|
offerHtml,
|
||||||
verifiedMode,
|
verifiedMode,
|
||||||
} = course;
|
} = course;
|
||||||
|
|
||||||
// Below the tabs, above the breadcrumbs alerts (appearing in the order listed here)
|
// Below the tabs, above the breadcrumbs alerts (appearing in the order listed here)
|
||||||
const offerAlert = useOfferAlert(offerHtml, 'course');
|
const offerAlert = useOfferAlert(offerHtml, 'course');
|
||||||
useAccessExpirationAlert(courseId);
|
const accessExpirationAlert = useAccessExpirationAlert(courseExpiredMessage, 'course');
|
||||||
|
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
const celebrateFirstSection = celebrations && celebrations.firstSection;
|
const celebrateFirstSection = celebrations && celebrations.firstSection;
|
||||||
@@ -64,7 +59,7 @@ function Course({
|
|||||||
className="my-3"
|
className="my-3"
|
||||||
topic="course"
|
topic="course"
|
||||||
customAlerts={{
|
customAlerts={{
|
||||||
clientAccessExpirationAlert: AccessExpirationAlert,
|
...accessExpirationAlert,
|
||||||
...offerAlert,
|
...offerAlert,
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
|
|||||||
Reference in New Issue
Block a user