Skip to content

Commit

Permalink
feat: optional xblocks
Browse files Browse the repository at this point in the history
  • Loading branch information
DanielVZ96 committed Feb 25, 2024
1 parent 21698b4 commit eb4628e
Show file tree
Hide file tree
Showing 13 changed files with 81 additions and 11 deletions.
5 changes: 5 additions & 0 deletions src/course-home/data/__factories__/progressTabData.factory.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,11 @@ Factory.define('progressTabData')
incomplete_count: 1,
locked_count: 0,
},
optional_completion_summary: {
complete_count: 1,
incomplete_count: 1,
locked_count: 0,
},
course_grade: {
letter_grade: 'pass',
percent: 1,
Expand Down
7 changes: 7 additions & 0 deletions src/course-home/data/__snapshots__/redux.test.js.snap
Original file line number Diff line number Diff line change
Expand Up @@ -428,6 +428,7 @@ Object {
"complete": false,
"courseId": "course-v1:edX+DemoX+Demo_Course",
"id": "block-v1:edX+DemoX+Demo_Course+type@chapter+block@bcdabcdabcdabcdabcdabcdabcdabcd2",
"optional": undefined,
"resumeBlock": false,
"sequenceIds": Array [
"block-v1:edX+DemoX+Demo_Course+type@sequential+block@bcdabcdabcdabcdabcdabcdabcdabcd1",
Expand All @@ -444,6 +445,7 @@ Object {
"effortTime": 15,
"icon": null,
"id": "block-v1:edX+DemoX+Demo_Course+type@sequential+block@bcdabcdabcdabcdabcdabcdabcdabcd1",
"optional": undefined,
"sectionId": "block-v1:edX+DemoX+Demo_Course+type@chapter+block@bcdabcdabcdabcdabcdabcdabcdabcd2",
"showLink": true,
"title": "Title of Sequence",
Expand Down Expand Up @@ -636,6 +638,11 @@ Object {
},
"hasScheduledContent": false,
"id": "course-v1:edX+DemoX+Demo_Course",
"optionalCompletionSummary": Object {
"completeCount": 1,
"incompleteCount": 1,
"lockedCount": 0,
},
"sectionScores": Array [
Object {
"displayName": "First section",
Expand Down
2 changes: 2 additions & 0 deletions src/course-home/data/api.js
Original file line number Diff line number Diff line change
Expand Up @@ -136,6 +136,7 @@ export function normalizeOutlineBlocks(courseId, blocks) {
title: block.display_name,
resumeBlock: block.resume_block,
sequenceIds: block.children || [],
optional: block.optional_content,
};
break;

Expand All @@ -152,6 +153,7 @@ export function normalizeOutlineBlocks(courseId, blocks) {
// link in the outline (even though we ignore the given url and use an internal <Link> to ourselves).
showLink: !!block.lms_web_url,
title: block.display_name,
optional: block.optional_content,
};
break;

Expand Down
4 changes: 3 additions & 1 deletion src/course-home/outline-tab/Section.jsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import React, { useEffect, useState } from 'react';
import PropTypes from 'prop-types';
import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
import { Collapsible, IconButton } from '@edx/paragon';
import { Badge, Collapsible, IconButton } from '@edx/paragon';
import { faCheckCircle as fasCheckCircle, faMinus, faPlus } from '@fortawesome/free-solid-svg-icons';
import { faCheckCircle as farCheckCircle } from '@fortawesome/free-regular-svg-icons';
import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
Expand All @@ -23,6 +23,7 @@ const Section = ({
complete,
sequenceIds,
title,
optional,
} = section;
const {
courseBlocks: {
Expand Down Expand Up @@ -64,6 +65,7 @@ const Section = ({
</div>
<div className="col-10 ml-3 p-0 font-weight-bold text-dark-500">
<span className="align-middle">{title}</span>
<Badge className="ml-2" variant="light" hidden={!optional}>{intl.formatMessage(messages.optionalContent)}</Badge>
<span className="sr-only">
, {intl.formatMessage(complete ? messages.completedSection : messages.incompleteSection)}
</span>
Expand Down
4 changes: 4 additions & 0 deletions src/course-home/outline-tab/SequenceLink.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ const SequenceLink = ({
due,
showLink,
title,
optional,
} = sequence;
const {
userTimezone,
Expand Down Expand Up @@ -115,6 +116,9 @@ const SequenceLink = ({
</div>
</div>
<div className="row w-100 m-0 ml-3 pl-3">
<small className="text-body pl-2 pr-0">
{optional ? intl.formatMessage(messages.optionalContent) : ''}
</small>
<small className="text-body pl-2">
{due ? dueDateMessage : noDueDateMessage}
</small>
Expand Down
5 changes: 5 additions & 0 deletions src/course-home/outline-tab/messages.js
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,11 @@ const messages = defineMessages({
defaultMessage: 'Open',
description: 'A button to open the given section of the course outline',
},
optionalContent: {
id: 'learning.outline.optionalBlock',
defaultMessage: 'Optional',
description: 'Used as a label to indicate that a section, sequence, or unit is optional.',
},
proctoringInfoPanel: {
id: 'learning.proctoringPanel.header',
defaultMessage: 'This course contains proctored exams',
Expand Down
20 changes: 20 additions & 0 deletions src/course-home/progress-tab/ProgressTab.test.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -262,6 +262,11 @@ describe('Progress Tab', () => {
incomplete_count: 1,
locked_count: 1,
},
optional_completion_summary: {
complete_count: 1,
incomplete_count: 1,
locked_count: 0,
},
verified_mode: {
access_expiration_date: '2050-01-01T12:00:00',
currency: 'USD',
Expand Down Expand Up @@ -304,6 +309,11 @@ describe('Progress Tab', () => {
incomplete_count: 1,
locked_count: 1,
},
optional_completion_summary: {
complete_count: 1,
incomplete_count: 1,
locked_count: 0,
},
verified_mode: {
access_expiration_date: '2050-01-01T12:00:00',
currency: 'USD',
Expand Down Expand Up @@ -364,6 +374,11 @@ describe('Progress Tab', () => {
incomplete_count: 1,
locked_count: 1,
},
optional_completion_summary: {
complete_count: 1,
incomplete_count: 1,
locked_count: 0,
},
section_scores: [
{
display_name: 'First section',
Expand Down Expand Up @@ -402,6 +417,11 @@ describe('Progress Tab', () => {
incomplete_count: 1,
locked_count: 1,
},
optional_completion_summary: {
complete_count: 1,
incomplete_count: 1,
locked_count: 0,
},
verified_mode: {
access_expiration_date: '2050-01-01T12:00:00',
currency: 'USD',
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,25 +3,28 @@ import { useSelector } from 'react-redux';
import {
getLocale, injectIntl, intlShape, isRtl,
} from '@edx/frontend-platform/i18n';
import PropTypes from 'prop-types';
import { useModel } from '../../../generic/model-store';

import CompleteDonutSegment from './CompleteDonutSegment';
import IncompleteDonutSegment from './IncompleteDonutSegment';
import LockedDonutSegment from './LockedDonutSegment';
import messages from './messages';

const CompletionDonutChart = ({ intl }) => {
const CompletionDonutChart = ({ intl, optional }) => {
const {
courseId,
} = useSelector(state => state.courseHome);

const key = optional ? 'optionalCompletionSummary' : 'completionSummary';
const label = optional ? intl.formatMessage(messages.optionalDonutLabel) : intl.formatMessage(messages.donutLabel);

const progress = useModel('progress', courseId);
const {
completionSummary: {
completeCount,
incompleteCount,
lockedCount,
},
} = useModel('progress', courseId);
completeCount,
incompleteCount,
lockedCount,
} = progress[key];

const numTotalUnits = completeCount + incompleteCount + lockedCount;
const completePercentage = completeCount ? Number(((completeCount / numTotalUnits) * 100).toFixed(0)) : 0;
Expand All @@ -30,6 +33,10 @@ const CompletionDonutChart = ({ intl }) => {

const isLocaleRtl = isRtl(getLocale());

if (optional && numTotalUnits === 0) {
return <></>;

Check warning on line 37 in src/course-home/progress-tab/course-completion/CompletionDonutChart.jsx

View check run for this annotation

Codecov / codecov/patch

src/course-home/progress-tab/course-completion/CompletionDonutChart.jsx#L37

Added line #L37 was not covered by tests
}

return (
<>
<svg role="img" width="50%" height="100%" viewBox="0 0 42 42" className="donut" style={{ maxWidth: '178px' }} aria-hidden="true">
Expand All @@ -42,7 +49,7 @@ const CompletionDonutChart = ({ intl }) => {
{completePercentage}{isLocaleRtl && '\u200f'}%
</text>
<text x="50%" y="50%" className="donut-chart-label">
{intl.formatMessage(messages.donutLabel)}
{label}
</text>
</g>
<IncompleteDonutSegment incompletePercentage={incompletePercentage} />
Expand All @@ -62,8 +69,13 @@ const CompletionDonutChart = ({ intl }) => {
);
};

CompletionDonutChart.defaultProps = {
optional: false,
};

CompletionDonutChart.propTypes = {
intl: intlShape.isRequired,
optional: PropTypes.bool,
};

export default injectIntl(CompletionDonutChart);
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,8 @@ const CourseCompletion = ({ intl }) => (
</p>
</div>
<div className="col-12 col-sm-6 col-md-5 mt-sm-n3 p-0 text-center">
<CompletionDonutChart />
<CompletionDonutChart optional={false} />
<CompletionDonutChart optional />
</div>
</div>
</section>
Expand Down
5 changes: 5 additions & 0 deletions src/course-home/progress-tab/course-completion/messages.js
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,11 @@ const messages = defineMessages({
defaultMessage: 'completed',
description: 'Label text for progress donut chart',
},
optionalDonutLabel: {
id: 'progress.completion.optionalDonut.label',
defaultMessage: 'optional',
description: 'Label text for optional progress donut chart',
},
completionBody: {
id: 'progress.completion.body',
defaultMessage: 'This represents how much of the course content you have completed. Note that some content may not yet be released.',
Expand Down
3 changes: 2 additions & 1 deletion src/courseware/course/sequence/Unit.jsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { getConfig } from '@edx/frontend-platform';
import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
import { AppContext, ErrorPage } from '@edx/frontend-platform/react';
import { Modal } from '@edx/paragon';
import { Modal, Badge } from '@edx/paragon';
import PropTypes from 'prop-types';
import React, {
Suspense, useCallback, useContext, useEffect, useLayoutEffect, useState,
Expand Down Expand Up @@ -155,6 +155,7 @@ const Unit = ({
return (
<div className="unit">
<h1 className="mb-0 h3">{unit.title}</h1>
<Badge className="ml-2" variant="light" hidden={!unit.optional}>{intl.formatMessage(messages.optionalContent)}</Badge>
<h2 className="sr-only">{intl.formatMessage(messages.headerPlaceholder)}</h2>
<BookmarkButton
unitId={unit.id}
Expand Down
5 changes: 5 additions & 0 deletions src/courseware/course/sequence/messages.js
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,11 @@ const messages = defineMessages({
defaultMessage: 'There is no content here.',
description: 'Message shown when there is no content to show a user inside a learning sequence.',
},
optionalContent: {
id: 'learn.sequence.optionalBlock',
defaultMessage: 'Optional',
description: 'Used as a label to indicate that a section, sequence, or unit is optional.',
},
});

export default messages;
1 change: 1 addition & 0 deletions src/courseware/data/api.js
Original file line number Diff line number Diff line change
Expand Up @@ -169,6 +169,7 @@ function normalizeSequenceMetadata(sequence) {
contentType: unit.type,
graded: unit.graded,
containsContentTypeGatedContent: unit.contains_content_type_gated_content,
optional: unit.optional_content,
})),
};
}
Expand Down

0 comments on commit eb4628e

Please sign in to comment.