Compare commits
2 Commits
dependabot
...
mikix/expi
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
d67f46865b | ||
|
|
ef38667751 |
@@ -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';
|
|
||||||
|
|||||||
@@ -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 OfferAlert({ payload }) {
|
function OfferAlert({ 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,15 +1,19 @@
|
|||||||
/* eslint-disable import/prefer-default-export */
|
import React from 'react';
|
||||||
import { useModel } from '../../generic/model-store';
|
|
||||||
import { useAlert } from '../../generic/user-messages';
|
import { useAlert } from '../../generic/user-messages';
|
||||||
|
|
||||||
export function useOfferAlert(courseId) {
|
const OfferAlert = React.lazy(() => import('./OfferAlert'));
|
||||||
const course = useModel('courses', courseId);
|
|
||||||
const rawHtml = (course && course.offerHtml) || null;
|
export function useOfferAlert(offerHtml, topic) {
|
||||||
|
const rawHtml = offerHtml || null;
|
||||||
const isVisible = !!rawHtml; // if it exists, show it.
|
const isVisible = !!rawHtml; // if it exists, show it.
|
||||||
|
|
||||||
useAlert(isVisible, {
|
useAlert(isVisible, {
|
||||||
code: 'clientOfferAlert',
|
code: 'clientOfferAlert',
|
||||||
topic: 'course',
|
topic,
|
||||||
payload: { rawHtml },
|
payload: { rawHtml },
|
||||||
});
|
});
|
||||||
|
|
||||||
|
return { clientOfferAlert: OfferAlert };
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export default useOfferAlert;
|
||||||
|
|||||||
@@ -1,2 +1 @@
|
|||||||
export { default as OfferAlert } from './OfferAlert';
|
export { default } from './hooks';
|
||||||
export { useOfferAlert } from './hooks';
|
|
||||||
|
|||||||
@@ -20,4 +20,5 @@ Factory.define('outlineTabData')
|
|||||||
can_enroll: true,
|
can_enroll: true,
|
||||||
extra_text: 'Contact the administrator.',
|
extra_text: 'Contact the administrator.',
|
||||||
})
|
})
|
||||||
.attr('handouts_html', [], () => '<ul><li>Handout 1</li></ul>');
|
.attr('handouts_html', [], () => '<ul><li>Handout 1</li></ul>')
|
||||||
|
.attr('offer_html', [], () => '<div>Great offer here</div>');
|
||||||
|
|||||||
@@ -204,6 +204,7 @@ Object {
|
|||||||
},
|
},
|
||||||
"handoutsHtml": "<ul><li>Handout 1</li></ul>",
|
"handoutsHtml": "<ul><li>Handout 1</li></ul>",
|
||||||
"id": "course-v1:edX+DemoX+Demo_Course_1",
|
"id": "course-v1:edX+DemoX+Demo_Course_1",
|
||||||
|
"offerHtml": "<div>Great offer here</div>",
|
||||||
"welcomeMessageHtml": undefined,
|
"welcomeMessageHtml": undefined,
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -69,18 +69,22 @@ 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);
|
||||||
const handoutsHtml = data.handouts_html;
|
const handoutsHtml = data.handouts_html;
|
||||||
|
const offerHtml = data.offer_html;
|
||||||
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,
|
||||||
|
offerHtml,
|
||||||
welcomeMessageHtml,
|
welcomeMessageHtml,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,11 +10,13 @@ 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';
|
||||||
import useEnrollmentAlert from '../../alerts/enrollment-alert';
|
import useEnrollmentAlert from '../../alerts/enrollment-alert';
|
||||||
import useLogistrationAlert from '../../alerts/logistration-alert';
|
import useLogistrationAlert from '../../alerts/logistration-alert';
|
||||||
|
import useOfferAlert from '../../alerts/offer-alert';
|
||||||
import { useModel } from '../../generic/model-store';
|
import { useModel } from '../../generic/model-store';
|
||||||
import WelcomeMessage from './widgets/WelcomeMessage';
|
import WelcomeMessage from './widgets/WelcomeMessage';
|
||||||
|
|
||||||
@@ -38,13 +40,20 @@ function OutlineTab({ intl }) {
|
|||||||
courses,
|
courses,
|
||||||
sections,
|
sections,
|
||||||
},
|
},
|
||||||
|
courseExpiredHtml,
|
||||||
|
offerHtml,
|
||||||
} = useModel('outline', courseId);
|
} = useModel('outline', courseId);
|
||||||
|
|
||||||
const certificateAvailableAlert = useCertificateAvailableAlert(courseId);
|
// Above the tab alerts (appearing in the order listed here)
|
||||||
const courseEndAlert = useCourseEndAlert(courseId);
|
|
||||||
const courseStartAlert = useCourseStartAlert(courseId);
|
|
||||||
const enrollmentAlert = useEnrollmentAlert(courseId);
|
|
||||||
const logistrationAlert = useLogistrationAlert();
|
const logistrationAlert = useLogistrationAlert();
|
||||||
|
const enrollmentAlert = useEnrollmentAlert(courseId);
|
||||||
|
|
||||||
|
// Below the course title alerts (appearing in the order listed here)
|
||||||
|
const offerAlert = useOfferAlert(offerHtml, 'outline-course-alerts');
|
||||||
|
const accessExpirationAlert = useAccessExpirationAlert(courseExpiredHtml, 'outline-course-alerts');
|
||||||
|
const courseStartAlert = useCourseStartAlert(courseId);
|
||||||
|
const courseEndAlert = useCourseEndAlert(courseId);
|
||||||
|
const certificateAvailableAlert = useCertificateAvailableAlert(courseId);
|
||||||
|
|
||||||
const rootCourseId = Object.keys(courses)[0];
|
const rootCourseId = Object.keys(courses)[0];
|
||||||
const { sectionIds } = courses[rootCourseId];
|
const { sectionIds } = courses[rootCourseId];
|
||||||
@@ -70,9 +79,11 @@ 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,
|
||||||
|
...offerAlert,
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
{sectionIds.map((sectionId) => (
|
{sectionIds.map((sectionId) => (
|
||||||
|
|||||||
@@ -5,8 +5,8 @@ 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,13 +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'));
|
|
||||||
const OfferAlert = React.lazy(() => import('../../alerts/offer-alert/OfferAlert'));
|
|
||||||
|
|
||||||
function Course({
|
function Course({
|
||||||
courseId,
|
courseId,
|
||||||
sequenceId,
|
sequenceId,
|
||||||
@@ -41,15 +34,18 @@ function Course({
|
|||||||
course,
|
course,
|
||||||
].filter(element => element != null).map(element => element.title);
|
].filter(element => element != null).map(element => element.title);
|
||||||
|
|
||||||
useOfferAlert(courseId);
|
|
||||||
useAccessExpirationAlert(courseId);
|
|
||||||
|
|
||||||
const {
|
const {
|
||||||
canShowUpgradeSock,
|
canShowUpgradeSock,
|
||||||
celebrations,
|
celebrations,
|
||||||
|
courseExpiredMessage,
|
||||||
|
offerHtml,
|
||||||
verifiedMode,
|
verifiedMode,
|
||||||
} = course;
|
} = course;
|
||||||
|
|
||||||
|
// Below the tabs, above the breadcrumbs alerts (appearing in the order listed here)
|
||||||
|
const offerAlert = useOfferAlert(offerHtml, 'course');
|
||||||
|
const accessExpirationAlert = useAccessExpirationAlert(courseExpiredMessage, 'course');
|
||||||
|
|
||||||
const dispatch = useDispatch();
|
const dispatch = useDispatch();
|
||||||
const celebrateFirstSection = celebrations && celebrations.firstSection;
|
const celebrateFirstSection = celebrations && celebrations.firstSection;
|
||||||
const celebrationOpen = shouldCelebrateOnSectionLoad(courseId, sequenceId, unitId, celebrateFirstSection, dispatch);
|
const celebrationOpen = shouldCelebrateOnSectionLoad(courseId, sequenceId, unitId, celebrateFirstSection, dispatch);
|
||||||
@@ -63,8 +59,8 @@ function Course({
|
|||||||
className="my-3"
|
className="my-3"
|
||||||
topic="course"
|
topic="course"
|
||||||
customAlerts={{
|
customAlerts={{
|
||||||
clientAccessExpirationAlert: AccessExpirationAlert,
|
...accessExpirationAlert,
|
||||||
clientOfferAlert: OfferAlert,
|
...offerAlert,
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<CourseBreadcrumbs
|
<CourseBreadcrumbs
|
||||||
|
|||||||
Reference in New Issue
Block a user