AA-122: Created Dates Widget on course home page (#82)
Including upcoming dates and a link to dates tab. Gives user ability to look at any important upcoming dates for their course and to navigate to upcoming assignments. Co-authored-by: Daphne Li-Chen <daphneli-chen@MacBook-Pro.local>
This commit is contained in:
@@ -1,41 +0,0 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
|
||||
export default function CourseDates({
|
||||
start,
|
||||
end,
|
||||
enrollmentStart,
|
||||
enrollmentEnd,
|
||||
enrollmentMode,
|
||||
isEnrolled,
|
||||
}) {
|
||||
return (
|
||||
<section>
|
||||
<h4>Upcoming Dates</h4>
|
||||
<div><strong>Course Start:</strong><br />{start}</div>
|
||||
<div><strong>Course End:</strong><br />{end}</div>
|
||||
<div><strong>Enrollment Start:</strong><br />{enrollmentStart}</div>
|
||||
<div><strong>Enrollment End:</strong><br />{enrollmentEnd}</div>
|
||||
<div><strong>Mode:</strong><br />{enrollmentMode}</div>
|
||||
<div>{isEnrolled ? 'Active Enrollment' : 'Inactive Enrollment'}</div>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
|
||||
CourseDates.propTypes = {
|
||||
start: PropTypes.string,
|
||||
end: PropTypes.string,
|
||||
enrollmentStart: PropTypes.string,
|
||||
enrollmentEnd: PropTypes.string,
|
||||
enrollmentMode: PropTypes.string,
|
||||
isEnrolled: PropTypes.bool,
|
||||
};
|
||||
|
||||
CourseDates.defaultProps = {
|
||||
start: null,
|
||||
end: null,
|
||||
enrollmentStart: null,
|
||||
enrollmentEnd: null,
|
||||
enrollmentMode: null,
|
||||
isEnrolled: false,
|
||||
};
|
||||
31
src/course-home/outline-tab/CourseDates.jsx
Normal file
31
src/course-home/outline-tab/CourseDates.jsx
Normal file
@@ -0,0 +1,31 @@
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { useModel } from '../../model-store';
|
||||
import DateSummary from './DateSummary';
|
||||
|
||||
export default function CourseDates({ courseId }) {
|
||||
const {
|
||||
datesWidget,
|
||||
} = useModel('outline', courseId);
|
||||
return (
|
||||
<section className="mb-3">
|
||||
<h4>Upcoming Dates</h4>
|
||||
{datesWidget.courseDateBlocks.map((courseDateBlock) => (
|
||||
<DateSummary
|
||||
key={courseDateBlock.title + courseDateBlock.date}
|
||||
dateBlock={courseDateBlock}
|
||||
userTimezone={datesWidget.userTimezone}
|
||||
/>
|
||||
))}
|
||||
<a className="font-weight-bold" href={datesWidget.datesTabLink}>View all course dates</a>
|
||||
</section>
|
||||
);
|
||||
}
|
||||
|
||||
CourseDates.propTypes = {
|
||||
courseId: PropTypes.string,
|
||||
};
|
||||
|
||||
CourseDates.defaultProps = {
|
||||
courseId: null,
|
||||
};
|
||||
@@ -5,7 +5,7 @@ import {
|
||||
faBookmark, faCertificate, faInfo, faCalendar, faStar,
|
||||
} from '@fortawesome/free-solid-svg-icons';
|
||||
import { faNewspaper } from '@fortawesome/free-regular-svg-icons';
|
||||
import { useModel } from '../model-store';
|
||||
import { useModel } from '../../model-store';
|
||||
|
||||
|
||||
export default function CourseTools(
|
||||
62
src/course-home/outline-tab/DateSummary.jsx
Normal file
62
src/course-home/outline-tab/DateSummary.jsx
Normal file
@@ -0,0 +1,62 @@
|
||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||
import { faCalendarAlt } from '@fortawesome/free-regular-svg-icons';
|
||||
import { FormattedDate } from '@edx/frontend-platform/i18n';
|
||||
import React from 'react';
|
||||
import PropTypes from 'prop-types';
|
||||
import { isLearnerAssignment } from '../../dates-tab/utils';
|
||||
import './DateSummary.scss';
|
||||
|
||||
export default function DateSummary({
|
||||
dateBlock,
|
||||
userTimezone,
|
||||
}) {
|
||||
const linkedTitle = dateBlock.link && isLearnerAssignment(dateBlock);
|
||||
const timezoneFormatArgs = userTimezone ? { timeZone: userTimezone } : {};
|
||||
return (
|
||||
<section className="container p-0 mb-3">
|
||||
<div className="row">
|
||||
<FontAwesomeIcon icon={faCalendarAlt} className="ml-3 mt-1 mr-1" style={{ width: '20px' }} />
|
||||
<div className="ml-2 font-weight-bold">
|
||||
<FormattedDate
|
||||
value={dateBlock.date}
|
||||
day="numeric"
|
||||
month="short"
|
||||
weekday="short"
|
||||
year="numeric"
|
||||
{...timezoneFormatArgs}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
<div className="row ml-4 px-2">
|
||||
<div className="date-summary-text">
|
||||
{linkedTitle
|
||||
&& <div className="font-weight-bold mt-2"><a href={dateBlock.link}>{dateBlock.title}</a></div>}
|
||||
{!linkedTitle
|
||||
&& <div className="font-weight-bold mt-2">{dateBlock.title}</div>}
|
||||
</div>
|
||||
{dateBlock.description
|
||||
&& <div className="date-summary-text m-0 mt-1">{dateBlock.description}</div>}
|
||||
{!linkedTitle && dateBlock.link
|
||||
&& <a href={dateBlock.link} className="description-link">{dateBlock.linkText}</a>}
|
||||
</div>
|
||||
|
||||
</section>
|
||||
);
|
||||
}
|
||||
|
||||
DateSummary.propTypes = {
|
||||
dateBlock: PropTypes.shape({
|
||||
date: PropTypes.string.isRequired,
|
||||
dateType: PropTypes.string,
|
||||
description: PropTypes.string,
|
||||
link: PropTypes.string,
|
||||
linkText: PropTypes.string,
|
||||
title: PropTypes.string.isRequired,
|
||||
learnerHasAccess: PropTypes.bool,
|
||||
}).isRequired,
|
||||
userTimezone: PropTypes.string,
|
||||
};
|
||||
|
||||
DateSummary.defaultProps = {
|
||||
userTimezone: null,
|
||||
};
|
||||
8
src/course-home/outline-tab/DateSummary.scss
Normal file
8
src/course-home/outline-tab/DateSummary.scss
Normal file
@@ -0,0 +1,8 @@
|
||||
.date-summary-text {
|
||||
margin-left: 2px;
|
||||
flex-basis: 100%;
|
||||
}
|
||||
|
||||
.description-link {
|
||||
margin-left: 1px;
|
||||
}
|
||||
@@ -4,9 +4,9 @@ import { Button } from '@edx/paragon';
|
||||
|
||||
import { AlertList } from '../../user-messages';
|
||||
|
||||
import CourseDates from '../CourseDates';
|
||||
import CourseTools from '../CourseTools';
|
||||
import Section from '../Section';
|
||||
import CourseDates from './CourseDates';
|
||||
import CourseTools from './CourseTools';
|
||||
import Section from './Section';
|
||||
import { useModel } from '../../model-store';
|
||||
|
||||
// Note that we import from the component files themselves in the enrollment-alert package.
|
||||
@@ -78,6 +78,7 @@ export default function OutlineTab() {
|
||||
enrollmentEnd={enrollmentEnd}
|
||||
enrollmentMode={enrollmentMode}
|
||||
isEnrolled={isEnrolled}
|
||||
courseId={courseId}
|
||||
/>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -4,7 +4,7 @@ import { Collapsible } from '@edx/paragon';
|
||||
import { faChevronRight, faChevronDown } from '@fortawesome/free-solid-svg-icons';
|
||||
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
|
||||
import SequenceLink from './SequenceLink';
|
||||
import { useModel } from '../model-store';
|
||||
import { useModel } from '../../model-store';
|
||||
|
||||
export default function Section({ courseId, title, sequenceIds }) {
|
||||
const {
|
||||
@@ -187,8 +187,10 @@ export async function getOutlineTabData(courseId, version) {
|
||||
} = tabData;
|
||||
const courseBlocks = normalizeBlocks(courseId, data.course_blocks.blocks);
|
||||
const courseTools = camelCaseObject(data.course_tools);
|
||||
|
||||
return { courseTools, courseBlocks };
|
||||
const datesWidget = camelCaseObject(data.dates_widget);
|
||||
return {
|
||||
courseTools, courseBlocks, datesWidget,
|
||||
};
|
||||
}
|
||||
|
||||
function normalizeSequenceMetadata(sequence) {
|
||||
|
||||
Reference in New Issue
Block a user