From d1bb46eef33f038c8e1e5c4b0939cc24d72af46e Mon Sep 17 00:00:00 2001 From: Carla Duarte Date: Wed, 23 Jun 2021 09:42:12 -0400 Subject: [PATCH] AA-815: ui and a11y progress tab fixes (#494) --- .../data/__snapshots__/redux.test.js.snap | 3 ++ src/course-home/data/slice.js | 5 +++ src/course-home/progress-tab/ProgressTab.jsx | 17 +++++++--- .../CompleteDonutSegment.jsx | 32 +++++++++++++------ .../IncompleteDonutSegment.jsx | 4 +++ .../course-completion/LockedDonutSegment.jsx | 2 +- .../grades/course-grade/CourseGrade.jsx | 11 +++---- .../grades/course-grade/GradeBar.jsx | 7 ++-- .../grades/course-grade/GradeRangeTooltip.jsx | 2 ++ .../grades/detailed-grades/DetailedGrades.jsx | 2 ++ .../detailed-grades/DetailedGradesTable.jsx | 4 ++- .../grade-summary/AssignmentTypeCell.jsx | 12 ++++++- .../DroppableAssignmentFootnote.jsx | 8 ++++- .../grade-summary/GradeSummaryHeader.jsx | 5 +++ .../grade-summary/GradeSummaryTable.jsx | 2 +- 15 files changed, 84 insertions(+), 32 deletions(-) diff --git a/src/course-home/data/__snapshots__/redux.test.js.snap b/src/course-home/data/__snapshots__/redux.test.js.snap index 65459211..7a8a20b0 100644 --- a/src/course-home/data/__snapshots__/redux.test.js.snap +++ b/src/course-home/data/__snapshots__/redux.test.js.snap @@ -5,6 +5,7 @@ Object { "courseHome": Object { "courseId": "course-v1:edX+DemoX+Demo_Course_1", "courseStatus": "loaded", + "gradesFeatureIsLocked": false, "toastBodyLink": null, "toastBodyText": null, "toastHeader": "", @@ -300,6 +301,7 @@ Object { "courseHome": Object { "courseId": "course-v1:edX+DemoX+Demo_Course_1", "courseStatus": "loaded", + "gradesFeatureIsLocked": false, "toastBodyLink": null, "toastBodyText": null, "toastHeader": "", @@ -476,6 +478,7 @@ Object { "courseHome": Object { "courseId": "course-v1:edX+DemoX+Demo_Course_1", "courseStatus": "loaded", + "gradesFeatureIsLocked": false, "toastBodyLink": null, "toastBodyText": null, "toastHeader": "", diff --git a/src/course-home/data/slice.js b/src/course-home/data/slice.js index 7e037d7c..0cefaae3 100644 --- a/src/course-home/data/slice.js +++ b/src/course-home/data/slice.js @@ -10,6 +10,7 @@ const slice = createSlice({ initialState: { courseStatus: 'loading', courseId: null, + gradesFeatureIsLocked: false, toastBodyText: null, toastBodyLink: null, toastHeader: '', @@ -37,6 +38,9 @@ const slice = createSlice({ state.toastBodyText = linkText; state.toastHeader = header; }, + setGradesFeatureStatus: (state, { payload }) => { + state.gradesFeatureIsLocked = payload.gradesFeatureIsLocked; + }, }, }); @@ -45,6 +49,7 @@ export const { fetchTabSuccess, fetchTabFailure, setCallToActionToast, + setGradesFeatureStatus, } = slice.actions; export const { diff --git a/src/course-home/progress-tab/ProgressTab.jsx b/src/course-home/progress-tab/ProgressTab.jsx index 9dbb6570..f4f1a4a9 100644 --- a/src/course-home/progress-tab/ProgressTab.jsx +++ b/src/course-home/progress-tab/ProgressTab.jsx @@ -1,6 +1,6 @@ -import React from 'react'; +import React, { useEffect } from 'react'; import { layoutGenerator } from 'react-break'; -import { useSelector } from 'react-redux'; +import { useDispatch, useSelector } from 'react-redux'; import CertificateStatus from './certificate-status/CertificateStatus'; import CourseCompletion from './course-completion/CourseCompletion'; @@ -10,6 +10,7 @@ import GradeSummary from './grades/grade-summary/GradeSummary'; import ProgressHeader from './ProgressHeader'; import RelatedLinks from './related-links/RelatedLinks'; +import { setGradesFeatureStatus } from '../data/slice'; import { useModel } from '../../generic/model-store'; function ProgressTab() { @@ -22,8 +23,14 @@ function ProgressTab() { lockedCount, }, } = 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({ mobile: 0, @@ -43,7 +50,7 @@ function ProgressTab() { -
+
diff --git a/src/course-home/progress-tab/course-completion/CompleteDonutSegment.jsx b/src/course-home/progress-tab/course-completion/CompleteDonutSegment.jsx index 03d17e47..2615b270 100644 --- a/src/course-home/progress-tab/course-completion/CompleteDonutSegment.jsx +++ b/src/course-home/progress-tab/course-completion/CompleteDonutSegment.jsx @@ -7,6 +7,10 @@ import { OverlayTrigger, Popover } from '@edx/paragon'; import messages from './messages'; function CompleteDonutSegment({ completePercentage, intl, lockedPercentage }) { + if (!completePercentage) { + return null; + } + const [showCompletePopover, setShowCompletePopover] = useState(false); const completeSegmentOffset = (3.6 * completePercentage) / 8; @@ -24,15 +28,6 @@ function CompleteDonutSegment({ completePercentage, intl, lockedPercentage }) { onFocus={() => setShowCompletePopover(true)} tabIndex="-1" > - - {/* Tooltip */} + {/* Complete segment */} + + {/* Segment dividers */} {lockedPercentage > 0 && lockedPercentage < 100 && ( )} - {completePercentage < 100 && lockedPercentage < 100 && lockedPercentage + completePercentage === 100 && ( + {completePercentage < 100 && lockedPercentage > 0 && lockedPercentage < 100 + && lockedPercentage + completePercentage === 100 && ( 0) { + if (!lockedPercentage) { return null; } diff --git a/src/course-home/progress-tab/grades/course-grade/CourseGrade.jsx b/src/course-home/progress-tab/grades/course-grade/CourseGrade.jsx index 94156f12..65b5a817 100644 --- a/src/course-home/progress-tab/grades/course-grade/CourseGrade.jsx +++ b/src/course-home/progress-tab/grades/course-grade/CourseGrade.jsx @@ -13,12 +13,10 @@ import messages from '../messages'; function CourseGrade({ intl }) { const { courseId, + gradesFeatureIsLocked, } = useSelector(state => state.courseHome); const { - completionSummary: { - lockedCount, - }, gradingPolicy: { gradeRange, }, @@ -26,13 +24,12 @@ function CourseGrade({ intl }) { const passingGrade = Number((Math.min(...Object.values(gradeRange)) * 100).toFixed(0)); - const isLocked = lockedCount > 0; - const applyLockedOverlay = isLocked ? 'locked-overlay' : ''; + const applyLockedOverlay = gradesFeatureIsLocked ? 'locked-overlay' : ''; return (
- {isLocked && } -
+ {gradesFeatureIsLocked && } +

{intl.formatMessage(messages.grades)}

diff --git a/src/course-home/progress-tab/grades/course-grade/GradeBar.jsx b/src/course-home/progress-tab/grades/course-grade/GradeBar.jsx index 319528c3..424c13d3 100644 --- a/src/course-home/progress-tab/grades/course-grade/GradeBar.jsx +++ b/src/course-home/progress-tab/grades/course-grade/GradeBar.jsx @@ -12,12 +12,10 @@ import messages from '../messages'; function GradeBar({ intl, passingGrade }) { const { courseId, + gradesFeatureIsLocked, } = useSelector(state => state.courseHome); const { - completionSummary: { - lockedCount, - }, courseGrade: { isPassing, visiblePercent, @@ -26,8 +24,7 @@ function GradeBar({ intl, passingGrade }) { const currentGrade = Number((visiblePercent * 100).toFixed(0)); - const isLocked = lockedCount > 0; - const lockedTooltipClassName = isLocked ? 'locked-overlay' : ''; + const lockedTooltipClassName = gradesFeatureIsLocked ? 'locked-overlay' : ''; return (
diff --git a/src/course-home/progress-tab/grades/course-grade/GradeRangeTooltip.jsx b/src/course-home/progress-tab/grades/course-grade/GradeRangeTooltip.jsx index 81b01ce1..856fe07b 100644 --- a/src/course-home/progress-tab/grades/course-grade/GradeRangeTooltip.jsx +++ b/src/course-home/progress-tab/grades/course-grade/GradeRangeTooltip.jsx @@ -14,6 +14,7 @@ import messages from '../messages'; function GradeRangeTooltip({ intl, iconButtonClassName, passingGrade }) { const { courseId, + gradesFeatureIsLocked, } = useSelector(state => state.courseHome); const { @@ -67,6 +68,7 @@ function GradeRangeTooltip({ intl, iconButtonClassName, passingGrade }) { src={InfoOutline} iconAs={Icon} size="inline" + disabled={gradesFeatureIsLocked} /> ); diff --git a/src/course-home/progress-tab/grades/detailed-grades/DetailedGrades.jsx b/src/course-home/progress-tab/grades/detailed-grades/DetailedGrades.jsx index 908ec650..9b579ac1 100644 --- a/src/course-home/progress-tab/grades/detailed-grades/DetailedGrades.jsx +++ b/src/course-home/progress-tab/grades/detailed-grades/DetailedGrades.jsx @@ -16,6 +16,7 @@ function DetailedGrades({ intl }) { const { administrator } = getAuthenticatedUser(); const { courseId, + gradesFeatureIsLocked, } = useSelector(state => state.courseHome); const { org, @@ -39,6 +40,7 @@ function DetailedGrades({ intl }) { className="muted-link inline-link" destination={`${getConfig().LMS_BASE_URL}/courses/${courseId}/course`} onClick={logOutlineLinkClick} + tabIndex={gradesFeatureIsLocked ? '-1' : '0'} > {intl.formatMessage(messages.courseOutline)} diff --git a/src/course-home/progress-tab/grades/detailed-grades/DetailedGradesTable.jsx b/src/course-home/progress-tab/grades/detailed-grades/DetailedGradesTable.jsx index 77514bbe..fe8b673e 100644 --- a/src/course-home/progress-tab/grades/detailed-grades/DetailedGradesTable.jsx +++ b/src/course-home/progress-tab/grades/detailed-grades/DetailedGradesTable.jsx @@ -13,6 +13,7 @@ import { useModel } from '../../../../generic/model-store'; function DetailedGradesTable({ intl, sectionScores }) { const { courseId, + gradesFeatureIsLocked, } = useSelector(state => state.courseHome); const { org, @@ -43,10 +44,11 @@ function DetailedGradesTable({ intl, sectionScores }) { const title = ( { logSubsectionClicked(subsection.blockKey); }} + tabIndex={gradesFeatureIsLocked ? '-1' : '0'} > {subsection.displayName} diff --git a/src/course-home/progress-tab/grades/grade-summary/AssignmentTypeCell.jsx b/src/course-home/progress-tab/grades/grade-summary/AssignmentTypeCell.jsx index bdb79173..2ffaa3a5 100644 --- a/src/course-home/progress-tab/grades/grade-summary/AssignmentTypeCell.jsx +++ b/src/course-home/progress-tab/grades/grade-summary/AssignmentTypeCell.jsx @@ -1,13 +1,23 @@ import React from 'react'; +import { useSelector } from 'react-redux'; import PropTypes from 'prop-types'; function AssignmentTypeCell({ assignmentType, footnoteMarker, footnoteId }) { + const { + gradesFeatureIsLocked, + } = useSelector(state => state.courseHome); return (
{assignmentType} {footnoteId && footnoteMarker && ( - + {footnoteMarker} diff --git a/src/course-home/progress-tab/grades/grade-summary/DroppableAssignmentFootnote.jsx b/src/course-home/progress-tab/grades/grade-summary/DroppableAssignmentFootnote.jsx index f897b892..4d114fc8 100644 --- a/src/course-home/progress-tab/grades/grade-summary/DroppableAssignmentFootnote.jsx +++ b/src/course-home/progress-tab/grades/grade-summary/DroppableAssignmentFootnote.jsx @@ -1,4 +1,5 @@ import React from 'react'; +import { useSelector } from 'react-redux'; import PropTypes from 'prop-types'; 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'; function DroppableAssignmentFootnote({ footnotes, intl }) { + const { + gradesFeatureIsLocked, + } = useSelector(state => state.courseHome); return ( <> {intl.formatMessage(messages.footnotesTitle)} @@ -21,7 +25,9 @@ function DroppableAssignmentFootnote({ footnotes, intl }) { assignmentType: footnote.assignmentType, }} /> - {intl.formatMessage(messages.backToContent)} + + {intl.formatMessage(messages.backToContent)} + ))} diff --git a/src/course-home/progress-tab/grades/grade-summary/GradeSummaryHeader.jsx b/src/course-home/progress-tab/grades/grade-summary/GradeSummaryHeader.jsx index f13de058..8ee62924 100644 --- a/src/course-home/progress-tab/grades/grade-summary/GradeSummaryHeader.jsx +++ b/src/course-home/progress-tab/grades/grade-summary/GradeSummaryHeader.jsx @@ -1,4 +1,5 @@ import React, { useState } from 'react'; +import { useSelector } from 'react-redux'; import { injectIntl, intlShape } from '@edx/frontend-platform/i18n'; import { @@ -9,6 +10,9 @@ import { InfoOutline } from '@edx/paragon/icons'; import messages from '../messages'; function GradeSummaryHeader({ intl }) { + const { + gradesFeatureIsLocked, + } = useSelector(state => state.courseHome); const [showTooltip, setShowTooltip] = useState(false); return (
@@ -33,6 +37,7 @@ function GradeSummaryHeader({ intl }) { iconAs={Icon} className="mb-3" size="sm" + disabled={gradesFeatureIsLocked} />
diff --git a/src/course-home/progress-tab/grades/grade-summary/GradeSummaryTable.jsx b/src/course-home/progress-tab/grades/grade-summary/GradeSummaryTable.jsx index 9e229434..09a0edb9 100644 --- a/src/course-home/progress-tab/grades/grade-summary/GradeSummaryTable.jsx +++ b/src/course-home/progress-tab/grades/grade-summary/GradeSummaryTable.jsx @@ -46,7 +46,7 @@ function GradeSummaryTable({ intl }) { return { type: { footnoteId, footnoteMarker, type: assignment.type }, - weight: `${assignment.weight * 100}%`, + weight: `${(assignment.weight * 100).toFixed(0)}%`, grade: `${(assignment.averageGrade * 100).toFixed(0)}%`, weightedGrade: `${(assignment.weightedGrade * 100).toFixed(0)}%`, };