AA-815: ui and a11y progress tab fixes (#494)
This commit is contained in:
@@ -5,6 +5,7 @@ Object {
|
|||||||
"courseHome": Object {
|
"courseHome": Object {
|
||||||
"courseId": "course-v1:edX+DemoX+Demo_Course_1",
|
"courseId": "course-v1:edX+DemoX+Demo_Course_1",
|
||||||
"courseStatus": "loaded",
|
"courseStatus": "loaded",
|
||||||
|
"gradesFeatureIsLocked": false,
|
||||||
"toastBodyLink": null,
|
"toastBodyLink": null,
|
||||||
"toastBodyText": null,
|
"toastBodyText": null,
|
||||||
"toastHeader": "",
|
"toastHeader": "",
|
||||||
@@ -300,6 +301,7 @@ Object {
|
|||||||
"courseHome": Object {
|
"courseHome": Object {
|
||||||
"courseId": "course-v1:edX+DemoX+Demo_Course_1",
|
"courseId": "course-v1:edX+DemoX+Demo_Course_1",
|
||||||
"courseStatus": "loaded",
|
"courseStatus": "loaded",
|
||||||
|
"gradesFeatureIsLocked": false,
|
||||||
"toastBodyLink": null,
|
"toastBodyLink": null,
|
||||||
"toastBodyText": null,
|
"toastBodyText": null,
|
||||||
"toastHeader": "",
|
"toastHeader": "",
|
||||||
@@ -476,6 +478,7 @@ Object {
|
|||||||
"courseHome": Object {
|
"courseHome": Object {
|
||||||
"courseId": "course-v1:edX+DemoX+Demo_Course_1",
|
"courseId": "course-v1:edX+DemoX+Demo_Course_1",
|
||||||
"courseStatus": "loaded",
|
"courseStatus": "loaded",
|
||||||
|
"gradesFeatureIsLocked": false,
|
||||||
"toastBodyLink": null,
|
"toastBodyLink": null,
|
||||||
"toastBodyText": null,
|
"toastBodyText": null,
|
||||||
"toastHeader": "",
|
"toastHeader": "",
|
||||||
|
|||||||
@@ -10,6 +10,7 @@ const slice = createSlice({
|
|||||||
initialState: {
|
initialState: {
|
||||||
courseStatus: 'loading',
|
courseStatus: 'loading',
|
||||||
courseId: null,
|
courseId: null,
|
||||||
|
gradesFeatureIsLocked: false,
|
||||||
toastBodyText: null,
|
toastBodyText: null,
|
||||||
toastBodyLink: null,
|
toastBodyLink: null,
|
||||||
toastHeader: '',
|
toastHeader: '',
|
||||||
@@ -37,6 +38,9 @@ const slice = createSlice({
|
|||||||
state.toastBodyText = linkText;
|
state.toastBodyText = linkText;
|
||||||
state.toastHeader = header;
|
state.toastHeader = header;
|
||||||
},
|
},
|
||||||
|
setGradesFeatureStatus: (state, { payload }) => {
|
||||||
|
state.gradesFeatureIsLocked = payload.gradesFeatureIsLocked;
|
||||||
|
},
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|
||||||
@@ -45,6 +49,7 @@ export const {
|
|||||||
fetchTabSuccess,
|
fetchTabSuccess,
|
||||||
fetchTabFailure,
|
fetchTabFailure,
|
||||||
setCallToActionToast,
|
setCallToActionToast,
|
||||||
|
setGradesFeatureStatus,
|
||||||
} = slice.actions;
|
} = slice.actions;
|
||||||
|
|
||||||
export const {
|
export const {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import React from 'react';
|
import React, { useEffect } from 'react';
|
||||||
import { layoutGenerator } from 'react-break';
|
import { layoutGenerator } from 'react-break';
|
||||||
import { useSelector } from 'react-redux';
|
import { useDispatch, useSelector } from 'react-redux';
|
||||||
|
|
||||||
import CertificateStatus from './certificate-status/CertificateStatus';
|
import CertificateStatus from './certificate-status/CertificateStatus';
|
||||||
import CourseCompletion from './course-completion/CourseCompletion';
|
import CourseCompletion from './course-completion/CourseCompletion';
|
||||||
@@ -10,6 +10,7 @@ import GradeSummary from './grades/grade-summary/GradeSummary';
|
|||||||
import ProgressHeader from './ProgressHeader';
|
import ProgressHeader from './ProgressHeader';
|
||||||
import RelatedLinks from './related-links/RelatedLinks';
|
import RelatedLinks from './related-links/RelatedLinks';
|
||||||
|
|
||||||
|
import { setGradesFeatureStatus } from '../data/slice';
|
||||||
import { useModel } from '../../generic/model-store';
|
import { useModel } from '../../generic/model-store';
|
||||||
|
|
||||||
function ProgressTab() {
|
function ProgressTab() {
|
||||||
@@ -22,8 +23,14 @@ function ProgressTab() {
|
|||||||
lockedCount,
|
lockedCount,
|
||||||
},
|
},
|
||||||
} = useModel('progress', courseId);
|
} = useModel('progress', courseId);
|
||||||
const isLocked = lockedCount > 0;
|
|
||||||
const applyLockedOverlay = isLocked ? 'locked-overlay' : '';
|
const gradesFeatureIsLocked = lockedCount > 0;
|
||||||
|
const applyLockedOverlay = gradesFeatureIsLocked ? 'locked-overlay' : '';
|
||||||
|
|
||||||
|
const dispatch = useDispatch();
|
||||||
|
useEffect(() => {
|
||||||
|
dispatch(setGradesFeatureStatus({ gradesFeatureIsLocked }));
|
||||||
|
}, []);
|
||||||
|
|
||||||
const layout = layoutGenerator({
|
const layout = layoutGenerator({
|
||||||
mobile: 0,
|
mobile: 0,
|
||||||
@@ -43,7 +50,7 @@ function ProgressTab() {
|
|||||||
<CertificateStatus />
|
<CertificateStatus />
|
||||||
</OnMobile>
|
</OnMobile>
|
||||||
<CourseGrade />
|
<CourseGrade />
|
||||||
<div className={`grades my-4 p-4 rounded shadow-sm ${applyLockedOverlay}`} aria-hidden={isLocked}>
|
<div className={`grades my-4 p-4 rounded shadow-sm ${applyLockedOverlay}`} aria-hidden={gradesFeatureIsLocked}>
|
||||||
<GradeSummary />
|
<GradeSummary />
|
||||||
<DetailedGrades />
|
<DetailedGrades />
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -7,6 +7,10 @@ import { OverlayTrigger, Popover } from '@edx/paragon';
|
|||||||
import messages from './messages';
|
import messages from './messages';
|
||||||
|
|
||||||
function CompleteDonutSegment({ completePercentage, intl, lockedPercentage }) {
|
function CompleteDonutSegment({ completePercentage, intl, lockedPercentage }) {
|
||||||
|
if (!completePercentage) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
const [showCompletePopover, setShowCompletePopover] = useState(false);
|
const [showCompletePopover, setShowCompletePopover] = useState(false);
|
||||||
|
|
||||||
const completeSegmentOffset = (3.6 * completePercentage) / 8;
|
const completeSegmentOffset = (3.6 * completePercentage) / 8;
|
||||||
@@ -24,15 +28,6 @@ function CompleteDonutSegment({ completePercentage, intl, lockedPercentage }) {
|
|||||||
onFocus={() => setShowCompletePopover(true)}
|
onFocus={() => setShowCompletePopover(true)}
|
||||||
tabIndex="-1"
|
tabIndex="-1"
|
||||||
>
|
>
|
||||||
<circle
|
|
||||||
className="donut-segment complete-stroke"
|
|
||||||
cx="21"
|
|
||||||
cy="21"
|
|
||||||
r="15.91549430918954"
|
|
||||||
strokeDasharray={`${completePercentage} ${100 - completePercentage}`}
|
|
||||||
strokeDashoffset={lockedSegmentOffset + completePercentage}
|
|
||||||
/>
|
|
||||||
|
|
||||||
{/* Tooltip */}
|
{/* Tooltip */}
|
||||||
<OverlayTrigger
|
<OverlayTrigger
|
||||||
show={showCompletePopover}
|
show={showCompletePopover}
|
||||||
@@ -49,16 +44,33 @@ function CompleteDonutSegment({ completePercentage, intl, lockedPercentage }) {
|
|||||||
<rect x="19" y="3" style={{ transform: `rotate(${completeTooltipDegree}deg)` }} />
|
<rect x="19" y="3" style={{ transform: `rotate(${completeTooltipDegree}deg)` }} />
|
||||||
</OverlayTrigger>
|
</OverlayTrigger>
|
||||||
|
|
||||||
|
{/* Complete segment */}
|
||||||
|
<circle
|
||||||
|
className="donut-segment complete-stroke"
|
||||||
|
cx="21"
|
||||||
|
cy="21"
|
||||||
|
r="15.91549430918954"
|
||||||
|
strokeDasharray={`${completePercentage} ${100 - completePercentage}`}
|
||||||
|
strokeDashoffset={lockedSegmentOffset + completePercentage}
|
||||||
|
/>
|
||||||
|
|
||||||
{/* Segment dividers */}
|
{/* Segment dividers */}
|
||||||
{lockedPercentage > 0 && lockedPercentage < 100 && (
|
{lockedPercentage > 0 && lockedPercentage < 100 && (
|
||||||
<circle
|
<circle
|
||||||
|
cx="21"
|
||||||
|
cy="21"
|
||||||
|
r="15.91549430918954"
|
||||||
className="donut-segment divider-stroke"
|
className="donut-segment divider-stroke"
|
||||||
strokeDasharray="0.3 99.7"
|
strokeDasharray="0.3 99.7"
|
||||||
strokeDashoffset={0.15 + lockedSegmentOffset}
|
strokeDashoffset={0.15 + lockedSegmentOffset}
|
||||||
/>
|
/>
|
||||||
)}
|
)}
|
||||||
{completePercentage < 100 && lockedPercentage < 100 && lockedPercentage + completePercentage === 100 && (
|
{completePercentage < 100 && lockedPercentage > 0 && lockedPercentage < 100
|
||||||
|
&& lockedPercentage + completePercentage === 100 && (
|
||||||
<circle
|
<circle
|
||||||
|
cx="21"
|
||||||
|
cy="21"
|
||||||
|
r="15.91549430918954"
|
||||||
className="donut-segment divider-stroke"
|
className="donut-segment divider-stroke"
|
||||||
strokeDasharray="0.3 99.7"
|
strokeDasharray="0.3 99.7"
|
||||||
strokeDashoffset="25.15"
|
strokeDashoffset="25.15"
|
||||||
|
|||||||
@@ -7,6 +7,10 @@ import { OverlayTrigger, Popover } from '@edx/paragon';
|
|||||||
import messages from './messages';
|
import messages from './messages';
|
||||||
|
|
||||||
function IncompleteDonutSegment({ incompletePercentage, intl }) {
|
function IncompleteDonutSegment({ incompletePercentage, intl }) {
|
||||||
|
if (!incompletePercentage) {
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
|
||||||
const [showIncompletePopover, setShowIncompletePopover] = useState(false);
|
const [showIncompletePopover, setShowIncompletePopover] = useState(false);
|
||||||
|
|
||||||
const incompleteSegmentOffset = (3.6 * incompletePercentage) / 16;
|
const incompleteSegmentOffset = (3.6 * incompletePercentage) / 16;
|
||||||
|
|||||||
@@ -9,7 +9,7 @@ import messages from './messages';
|
|||||||
function LockedDonutSegment({ intl, lockedPercentage }) {
|
function LockedDonutSegment({ intl, lockedPercentage }) {
|
||||||
const [showLockedPopover, setShowLockedPopover] = useState(false);
|
const [showLockedPopover, setShowLockedPopover] = useState(false);
|
||||||
|
|
||||||
if (!lockedPercentage > 0) {
|
if (!lockedPercentage) {
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -13,12 +13,10 @@ import messages from '../messages';
|
|||||||
function CourseGrade({ intl }) {
|
function CourseGrade({ intl }) {
|
||||||
const {
|
const {
|
||||||
courseId,
|
courseId,
|
||||||
|
gradesFeatureIsLocked,
|
||||||
} = useSelector(state => state.courseHome);
|
} = useSelector(state => state.courseHome);
|
||||||
|
|
||||||
const {
|
const {
|
||||||
completionSummary: {
|
|
||||||
lockedCount,
|
|
||||||
},
|
|
||||||
gradingPolicy: {
|
gradingPolicy: {
|
||||||
gradeRange,
|
gradeRange,
|
||||||
},
|
},
|
||||||
@@ -26,13 +24,12 @@ function CourseGrade({ intl }) {
|
|||||||
|
|
||||||
const passingGrade = Number((Math.min(...Object.values(gradeRange)) * 100).toFixed(0));
|
const passingGrade = Number((Math.min(...Object.values(gradeRange)) * 100).toFixed(0));
|
||||||
|
|
||||||
const isLocked = lockedCount > 0;
|
const applyLockedOverlay = gradesFeatureIsLocked ? 'locked-overlay' : '';
|
||||||
const applyLockedOverlay = isLocked ? 'locked-overlay' : '';
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<section className="text-dark-700 my-4 rounded shadow-sm">
|
<section className="text-dark-700 my-4 rounded shadow-sm">
|
||||||
{isLocked && <CourseGradeHeader />}
|
{gradesFeatureIsLocked && <CourseGradeHeader />}
|
||||||
<div className={applyLockedOverlay}>
|
<div className={applyLockedOverlay} aria-hidden={gradesFeatureIsLocked}>
|
||||||
<div className="row w-100 m-0 p-4">
|
<div className="row w-100 m-0 p-4">
|
||||||
<div className="col-12 col-sm-6 p-0 pr-sm-2">
|
<div className="col-12 col-sm-6 p-0 pr-sm-2">
|
||||||
<h2>{intl.formatMessage(messages.grades)}</h2>
|
<h2>{intl.formatMessage(messages.grades)}</h2>
|
||||||
|
|||||||
@@ -12,12 +12,10 @@ import messages from '../messages';
|
|||||||
function GradeBar({ intl, passingGrade }) {
|
function GradeBar({ intl, passingGrade }) {
|
||||||
const {
|
const {
|
||||||
courseId,
|
courseId,
|
||||||
|
gradesFeatureIsLocked,
|
||||||
} = useSelector(state => state.courseHome);
|
} = useSelector(state => state.courseHome);
|
||||||
|
|
||||||
const {
|
const {
|
||||||
completionSummary: {
|
|
||||||
lockedCount,
|
|
||||||
},
|
|
||||||
courseGrade: {
|
courseGrade: {
|
||||||
isPassing,
|
isPassing,
|
||||||
visiblePercent,
|
visiblePercent,
|
||||||
@@ -26,8 +24,7 @@ function GradeBar({ intl, passingGrade }) {
|
|||||||
|
|
||||||
const currentGrade = Number((visiblePercent * 100).toFixed(0));
|
const currentGrade = Number((visiblePercent * 100).toFixed(0));
|
||||||
|
|
||||||
const isLocked = lockedCount > 0;
|
const lockedTooltipClassName = gradesFeatureIsLocked ? 'locked-overlay' : '';
|
||||||
const lockedTooltipClassName = isLocked ? 'locked-overlay' : '';
|
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="col-12 col-sm-6 align-self-center">
|
<div className="col-12 col-sm-6 align-self-center">
|
||||||
|
|||||||
@@ -14,6 +14,7 @@ import messages from '../messages';
|
|||||||
function GradeRangeTooltip({ intl, iconButtonClassName, passingGrade }) {
|
function GradeRangeTooltip({ intl, iconButtonClassName, passingGrade }) {
|
||||||
const {
|
const {
|
||||||
courseId,
|
courseId,
|
||||||
|
gradesFeatureIsLocked,
|
||||||
} = useSelector(state => state.courseHome);
|
} = useSelector(state => state.courseHome);
|
||||||
|
|
||||||
const {
|
const {
|
||||||
@@ -67,6 +68,7 @@ function GradeRangeTooltip({ intl, iconButtonClassName, passingGrade }) {
|
|||||||
src={InfoOutline}
|
src={InfoOutline}
|
||||||
iconAs={Icon}
|
iconAs={Icon}
|
||||||
size="inline"
|
size="inline"
|
||||||
|
disabled={gradesFeatureIsLocked}
|
||||||
/>
|
/>
|
||||||
</OverlayTrigger>
|
</OverlayTrigger>
|
||||||
);
|
);
|
||||||
|
|||||||
@@ -16,6 +16,7 @@ function DetailedGrades({ intl }) {
|
|||||||
const { administrator } = getAuthenticatedUser();
|
const { administrator } = getAuthenticatedUser();
|
||||||
const {
|
const {
|
||||||
courseId,
|
courseId,
|
||||||
|
gradesFeatureIsLocked,
|
||||||
} = useSelector(state => state.courseHome);
|
} = useSelector(state => state.courseHome);
|
||||||
const {
|
const {
|
||||||
org,
|
org,
|
||||||
@@ -39,6 +40,7 @@ function DetailedGrades({ intl }) {
|
|||||||
className="muted-link inline-link"
|
className="muted-link inline-link"
|
||||||
destination={`${getConfig().LMS_BASE_URL}/courses/${courseId}/course`}
|
destination={`${getConfig().LMS_BASE_URL}/courses/${courseId}/course`}
|
||||||
onClick={logOutlineLinkClick}
|
onClick={logOutlineLinkClick}
|
||||||
|
tabIndex={gradesFeatureIsLocked ? '-1' : '0'}
|
||||||
>
|
>
|
||||||
{intl.formatMessage(messages.courseOutline)}
|
{intl.formatMessage(messages.courseOutline)}
|
||||||
</Hyperlink>
|
</Hyperlink>
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import { useModel } from '../../../../generic/model-store';
|
|||||||
function DetailedGradesTable({ intl, sectionScores }) {
|
function DetailedGradesTable({ intl, sectionScores }) {
|
||||||
const {
|
const {
|
||||||
courseId,
|
courseId,
|
||||||
|
gradesFeatureIsLocked,
|
||||||
} = useSelector(state => state.courseHome);
|
} = useSelector(state => state.courseHome);
|
||||||
const {
|
const {
|
||||||
org,
|
org,
|
||||||
@@ -43,10 +44,11 @@ function DetailedGradesTable({ intl, sectionScores }) {
|
|||||||
const title = (
|
const title = (
|
||||||
<a
|
<a
|
||||||
href={subsection.url}
|
href={subsection.url}
|
||||||
className="text-dark-700 small"
|
className="muted-link small"
|
||||||
onClick={() => {
|
onClick={() => {
|
||||||
logSubsectionClicked(subsection.blockKey);
|
logSubsectionClicked(subsection.blockKey);
|
||||||
}}
|
}}
|
||||||
|
tabIndex={gradesFeatureIsLocked ? '-1' : '0'}
|
||||||
>
|
>
|
||||||
{subsection.displayName}
|
{subsection.displayName}
|
||||||
</a>
|
</a>
|
||||||
|
|||||||
@@ -1,13 +1,23 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import { useSelector } from 'react-redux';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
|
|
||||||
function AssignmentTypeCell({ assignmentType, footnoteMarker, footnoteId }) {
|
function AssignmentTypeCell({ assignmentType, footnoteMarker, footnoteId }) {
|
||||||
|
const {
|
||||||
|
gradesFeatureIsLocked,
|
||||||
|
} = useSelector(state => state.courseHome);
|
||||||
return (
|
return (
|
||||||
<div className="small">
|
<div className="small">
|
||||||
{assignmentType}
|
{assignmentType}
|
||||||
{footnoteId && footnoteMarker && (
|
{footnoteId && footnoteMarker && (
|
||||||
<sup>
|
<sup>
|
||||||
<a id={`${footnoteId}-ref`} className="text-dark-700" href={`#${footnoteId}-footnote`} aria-describedby="grade-summary-footnote-label">
|
<a
|
||||||
|
id={`${footnoteId}-ref`}
|
||||||
|
className="muted-link"
|
||||||
|
href={`#${footnoteId}-footnote`}
|
||||||
|
aria-describedby="grade-summary-footnote-label"
|
||||||
|
tabIndex={gradesFeatureIsLocked ? '-1' : '0'}
|
||||||
|
>
|
||||||
{footnoteMarker}
|
{footnoteMarker}
|
||||||
</a>
|
</a>
|
||||||
</sup>
|
</sup>
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import { useSelector } from 'react-redux';
|
||||||
import PropTypes from 'prop-types';
|
import PropTypes from 'prop-types';
|
||||||
|
|
||||||
import { FormattedMessage, injectIntl, intlShape } from '@edx/frontend-platform/i18n';
|
import { FormattedMessage, injectIntl, intlShape } from '@edx/frontend-platform/i18n';
|
||||||
@@ -6,6 +7,9 @@ import { FormattedMessage, injectIntl, intlShape } from '@edx/frontend-platform/
|
|||||||
import messages from '../messages';
|
import messages from '../messages';
|
||||||
|
|
||||||
function DroppableAssignmentFootnote({ footnotes, intl }) {
|
function DroppableAssignmentFootnote({ footnotes, intl }) {
|
||||||
|
const {
|
||||||
|
gradesFeatureIsLocked,
|
||||||
|
} = useSelector(state => state.courseHome);
|
||||||
return (
|
return (
|
||||||
<>
|
<>
|
||||||
<span id="grade-summary-footnote-label" className="sr-only">{intl.formatMessage(messages.footnotesTitle)}</span>
|
<span id="grade-summary-footnote-label" className="sr-only">{intl.formatMessage(messages.footnotesTitle)}</span>
|
||||||
@@ -21,7 +25,9 @@ function DroppableAssignmentFootnote({ footnotes, intl }) {
|
|||||||
assignmentType: footnote.assignmentType,
|
assignmentType: footnote.assignmentType,
|
||||||
}}
|
}}
|
||||||
/>
|
/>
|
||||||
<a className="sr-only" href={`#${footnote.id}-ref`}>{intl.formatMessage(messages.backToContent)}</a>
|
<a className="sr-only" href={`#${footnote.id}-ref`} tabIndex={gradesFeatureIsLocked ? '-1' : '0'}>
|
||||||
|
{intl.formatMessage(messages.backToContent)}
|
||||||
|
</a>
|
||||||
</li>
|
</li>
|
||||||
))}
|
))}
|
||||||
</ul>
|
</ul>
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
import React, { useState } from 'react';
|
import React, { useState } from 'react';
|
||||||
|
import { useSelector } from 'react-redux';
|
||||||
|
|
||||||
import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
|
import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
|
||||||
import {
|
import {
|
||||||
@@ -9,6 +10,9 @@ import { InfoOutline } from '@edx/paragon/icons';
|
|||||||
import messages from '../messages';
|
import messages from '../messages';
|
||||||
|
|
||||||
function GradeSummaryHeader({ intl }) {
|
function GradeSummaryHeader({ intl }) {
|
||||||
|
const {
|
||||||
|
gradesFeatureIsLocked,
|
||||||
|
} = useSelector(state => state.courseHome);
|
||||||
const [showTooltip, setShowTooltip] = useState(false);
|
const [showTooltip, setShowTooltip] = useState(false);
|
||||||
return (
|
return (
|
||||||
<div className="row w-100 m-0 align-items-center">
|
<div className="row w-100 m-0 align-items-center">
|
||||||
@@ -33,6 +37,7 @@ function GradeSummaryHeader({ intl }) {
|
|||||||
iconAs={Icon}
|
iconAs={Icon}
|
||||||
className="mb-3"
|
className="mb-3"
|
||||||
size="sm"
|
size="sm"
|
||||||
|
disabled={gradesFeatureIsLocked}
|
||||||
/>
|
/>
|
||||||
</OverlayTrigger>
|
</OverlayTrigger>
|
||||||
</div>
|
</div>
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ function GradeSummaryTable({ intl }) {
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
type: { footnoteId, footnoteMarker, type: assignment.type },
|
type: { footnoteId, footnoteMarker, type: assignment.type },
|
||||||
weight: `${assignment.weight * 100}%`,
|
weight: `${(assignment.weight * 100).toFixed(0)}%`,
|
||||||
grade: `${(assignment.averageGrade * 100).toFixed(0)}%`,
|
grade: `${(assignment.averageGrade * 100).toFixed(0)}%`,
|
||||||
weightedGrade: `${(assignment.weightedGrade * 100).toFixed(0)}%`,
|
weightedGrade: `${(assignment.weightedGrade * 100).toFixed(0)}%`,
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user