From a56fd7d0e14af2ca1606d36a31f5456f8ff18413 Mon Sep 17 00:00:00 2001 From: Kristin Aoki <42981026+KristinAoki@users.noreply.github.com> Date: Wed, 12 Mar 2025 15:43:27 -0400 Subject: [PATCH] feat: change blocked icon to lock icon (#1619) * feat: replace blocked icon with locked * refactor: replace injectIntl with useIntl * revert: temporary test change * fix: failing test * fix: wording of message description * fix: lingering lint error * fix: missing message variable --- .../progress-tab/ProgressHeader.jsx | 13 ++-- .../progress-tab/ProgressTab.test.jsx | 7 +- .../CompleteDonutSegment.jsx | 10 +-- .../CompletionDonutChart.jsx | 14 ++-- .../course-completion/CourseCompletion.jsx | 39 +++++------ .../IncompleteDonutSegment.jsx | 10 +-- .../course-completion/LockedDonutSegment.jsx | 10 +-- .../credit-information/CreditInformation.jsx | 41 ++--------- .../credit-information/messages.ts | 16 +++++ .../grades/course-grade/CourseGrade.jsx | 12 ++-- .../grades/course-grade/CourseGradeFooter.jsx | 9 ++- .../grades/course-grade/CourseGradeHeader.jsx | 13 ++-- .../course-grade/CurrentGradeTooltip.jsx | 11 ++- .../grades/course-grade/GradeBar.jsx | 11 ++- .../grades/course-grade/GradeRangeTooltip.jsx | 10 +-- .../course-grade/PassingGradeTooltip.jsx | 11 ++- .../grades/detailed-grades/DetailedGrades.jsx | 38 +++------- .../detailed-grades/DetailedGradesTable.jsx | 15 ++-- .../detailed-grades/ProblemScoreDrawer.jsx | 11 ++- .../detailed-grades/SubsectionTitleCell.jsx | 18 ++--- .../grade-summary/AssignmentTypeCell.jsx | 13 ++-- .../DroppableAssignmentFootnote.jsx | 22 +++--- .../grade-summary/GradeSummaryHeader.jsx | 70 ++++++++++++------- .../progress-tab/grades/messages.ts | 22 +++++- .../related-links/RelatedLinks.jsx | 13 ++-- 25 files changed, 210 insertions(+), 249 deletions(-) diff --git a/src/course-home/progress-tab/ProgressHeader.jsx b/src/course-home/progress-tab/ProgressHeader.jsx index 1d0fd56f..6223b1fc 100644 --- a/src/course-home/progress-tab/ProgressHeader.jsx +++ b/src/course-home/progress-tab/ProgressHeader.jsx @@ -1,7 +1,5 @@ -import React from 'react'; - import { getAuthenticatedUser } from '@edx/frontend-platform/auth'; -import { injectIntl, intlShape } from '@edx/frontend-platform/i18n'; +import { useIntl } from '@edx/frontend-platform/i18n'; import { Button } from '@openedx/paragon'; import { useSelector } from 'react-redux'; @@ -9,7 +7,8 @@ import { useModel } from '../../generic/model-store'; import messages from './messages'; -const ProgressHeader = ({ intl }) => { +const ProgressHeader = () => { + const intl = useIntl(); const { courseId, targetUserId, @@ -37,8 +36,4 @@ const ProgressHeader = ({ intl }) => { ); }; -ProgressHeader.propTypes = { - intl: intlShape.isRequired, -}; - -export default injectIntl(ProgressHeader); +export default ProgressHeader; diff --git a/src/course-home/progress-tab/ProgressTab.test.jsx b/src/course-home/progress-tab/ProgressTab.test.jsx index 1a9b1540..8871fa93 100644 --- a/src/course-home/progress-tab/ProgressTab.test.jsx +++ b/src/course-home/progress-tab/ProgressTab.test.jsx @@ -471,9 +471,12 @@ describe('Progress Tab', () => { await fetchAndRender(); expect(screen.getByText('limited feature')).toBeInTheDocument(); expect(screen.getByText('Unlock to work towards a certificate.')).toBeInTheDocument(); - expect(screen.queryAllByText('You have limited access to graded assignments as part of the audit track in this course.')).toHaveLength(2); + expect(screen.queryAllByText( + 'You have limited access to graded assignments as part of the audit track in this course.', + { exact: false }, + )).toHaveLength(2); - expect(screen.queryAllByTestId('blocked-icon')).toHaveLength(4); + expect(screen.queryAllByTestId('locked-icon')).toHaveLength(4); }); it('does not render subsections for which showGrades is false', async () => { diff --git a/src/course-home/progress-tab/course-completion/CompleteDonutSegment.jsx b/src/course-home/progress-tab/course-completion/CompleteDonutSegment.jsx index 37189157..5b685f15 100644 --- a/src/course-home/progress-tab/course-completion/CompleteDonutSegment.jsx +++ b/src/course-home/progress-tab/course-completion/CompleteDonutSegment.jsx @@ -1,12 +1,13 @@ -import React, { useState } from 'react'; +import { useState } from 'react'; import PropTypes from 'prop-types'; -import { injectIntl, intlShape } from '@edx/frontend-platform/i18n'; +import { useIntl } from '@edx/frontend-platform/i18n'; import { OverlayTrigger, Popover } from '@openedx/paragon'; import messages from './messages'; -const CompleteDonutSegment = ({ completePercentage, intl, lockedPercentage }) => { +const CompleteDonutSegment = ({ completePercentage, lockedPercentage }) => { + const intl = useIntl(); const [showCompletePopover, setShowCompletePopover] = useState(false); if (!completePercentage) { @@ -82,8 +83,7 @@ const CompleteDonutSegment = ({ completePercentage, intl, lockedPercentage }) => CompleteDonutSegment.propTypes = { completePercentage: PropTypes.number.isRequired, - intl: intlShape.isRequired, lockedPercentage: PropTypes.number.isRequired, }; -export default injectIntl(CompleteDonutSegment); +export default CompleteDonutSegment; diff --git a/src/course-home/progress-tab/course-completion/CompletionDonutChart.jsx b/src/course-home/progress-tab/course-completion/CompletionDonutChart.jsx index 8c008f0c..a74c3a0a 100644 --- a/src/course-home/progress-tab/course-completion/CompletionDonutChart.jsx +++ b/src/course-home/progress-tab/course-completion/CompletionDonutChart.jsx @@ -1,7 +1,4 @@ -import React from 'react'; -import { - getLocale, injectIntl, intlShape, isRtl, -} from '@edx/frontend-platform/i18n'; +import { getLocale, isRtl, useIntl } from '@edx/frontend-platform/i18n'; import { useContextId } from '../../../data/hooks'; import { useModel } from '../../../generic/model-store'; @@ -10,7 +7,8 @@ import IncompleteDonutSegment from './IncompleteDonutSegment'; import LockedDonutSegment from './LockedDonutSegment'; import messages from './messages'; -const CompletionDonutChart = ({ intl }) => { +const CompletionDonutChart = () => { + const intl = useIntl(); const courseId = useContextId(); const { @@ -60,8 +58,4 @@ const CompletionDonutChart = ({ intl }) => { ); }; -CompletionDonutChart.propTypes = { - intl: intlShape.isRequired, -}; - -export default injectIntl(CompletionDonutChart); +export default CompletionDonutChart; diff --git a/src/course-home/progress-tab/course-completion/CourseCompletion.jsx b/src/course-home/progress-tab/course-completion/CourseCompletion.jsx index 1fc7dfa9..4f85a081 100644 --- a/src/course-home/progress-tab/course-completion/CourseCompletion.jsx +++ b/src/course-home/progress-tab/course-completion/CourseCompletion.jsx @@ -1,27 +1,26 @@ -import React from 'react'; -import { injectIntl, intlShape } from '@edx/frontend-platform/i18n'; +import { useIntl } from '@edx/frontend-platform/i18n'; import CompletionDonutChart from './CompletionDonutChart'; import messages from './messages'; -const CourseCompletion = ({ intl }) => ( -
-
-
-

{intl.formatMessage(messages.courseCompletion)}

-

- {intl.formatMessage(messages.completionBody)} -

-
-
- -
-
-
-); +const CourseCompletion = () => { + const intl = useIntl(); -CourseCompletion.propTypes = { - intl: intlShape.isRequired, + return ( +
+
+
+

{intl.formatMessage(messages.courseCompletion)}

+

+ {intl.formatMessage(messages.completionBody)} +

+
+
+ +
+
+
+ ); }; -export default injectIntl(CourseCompletion); +export default CourseCompletion; diff --git a/src/course-home/progress-tab/course-completion/IncompleteDonutSegment.jsx b/src/course-home/progress-tab/course-completion/IncompleteDonutSegment.jsx index 444586ad..19d9c300 100644 --- a/src/course-home/progress-tab/course-completion/IncompleteDonutSegment.jsx +++ b/src/course-home/progress-tab/course-completion/IncompleteDonutSegment.jsx @@ -1,12 +1,13 @@ -import React, { useState } from 'react'; +import { useState } from 'react'; import PropTypes from 'prop-types'; -import { injectIntl, intlShape } from '@edx/frontend-platform/i18n'; +import { useIntl } from '@edx/frontend-platform/i18n'; import { OverlayTrigger, Popover } from '@openedx/paragon'; import messages from './messages'; -const IncompleteDonutSegment = ({ incompletePercentage, intl }) => { +const IncompleteDonutSegment = ({ incompletePercentage }) => { + const intl = useIntl(); const [showIncompletePopover, setShowIncompletePopover] = useState(false); if (!incompletePercentage) { @@ -53,7 +54,6 @@ const IncompleteDonutSegment = ({ incompletePercentage, intl }) => { IncompleteDonutSegment.propTypes = { incompletePercentage: PropTypes.number.isRequired, - intl: intlShape.isRequired, }; -export default injectIntl(IncompleteDonutSegment); +export default IncompleteDonutSegment; diff --git a/src/course-home/progress-tab/course-completion/LockedDonutSegment.jsx b/src/course-home/progress-tab/course-completion/LockedDonutSegment.jsx index bb60f689..c7fea85b 100644 --- a/src/course-home/progress-tab/course-completion/LockedDonutSegment.jsx +++ b/src/course-home/progress-tab/course-completion/LockedDonutSegment.jsx @@ -1,12 +1,13 @@ -import React, { useState } from 'react'; +import { useState } from 'react'; import PropTypes from 'prop-types'; import { OverlayTrigger, Popover } from '@openedx/paragon'; -import { injectIntl, intlShape } from '@edx/frontend-platform/i18n'; +import { useIntl } from '@edx/frontend-platform/i18n'; import messages from './messages'; -const LockedDonutSegment = ({ intl, lockedPercentage }) => { +const LockedDonutSegment = ({ lockedPercentage }) => { + const intl = useIntl(); const [showLockedPopover, setShowLockedPopover] = useState(false); if (!lockedPercentage) { @@ -65,8 +66,7 @@ const LockedDonutSegment = ({ intl, lockedPercentage }) => { }; LockedDonutSegment.propTypes = { - intl: intlShape.isRequired, lockedPercentage: PropTypes.number.isRequired, }; -export default injectIntl(LockedDonutSegment); +export default LockedDonutSegment; diff --git a/src/course-home/progress-tab/credit-information/CreditInformation.jsx b/src/course-home/progress-tab/credit-information/CreditInformation.jsx index 27843f9b..c12c4de2 100644 --- a/src/course-home/progress-tab/credit-information/CreditInformation.jsx +++ b/src/course-home/progress-tab/credit-information/CreditInformation.jsx @@ -1,6 +1,5 @@ -import React from 'react'; import { getConfig } from '@edx/frontend-platform'; -import { FormattedMessage, injectIntl, intlShape } from '@edx/frontend-platform/i18n'; +import { useIntl } from '@edx/frontend-platform/i18n'; import { CheckCircle, WarningFilled, WatchFilled } from '@openedx/paragon/icons'; import { Hyperlink, Icon } from '@openedx/paragon'; import { useContextId } from '../../../data/hooks'; @@ -10,7 +9,8 @@ import { DashboardLink } from '../../../shared/links'; import messages from './messages'; -const CreditInformation = ({ intl }) => { +const CreditInformation = () => { + const intl = useIntl(); const courseId = useContextId(); const { @@ -34,36 +34,13 @@ const CreditInformation = ({ intl }) => { switch (creditCourseRequirements.eligibilityStatus) { case 'not_eligible': - eligibilityStatus = ( - - ); + eligibilityStatus = intl.formatMessage(messages.creditNotEligibleStatus, { creditLink }); break; case 'eligible': - eligibilityStatus = ( - - ); + eligibilityStatus = intl.formatMessage(messages.creditEligibleStatus, { dashboardLink, creditLink }); break; case 'partial_eligible': - eligibilityStatus = ( - - ); + eligibilityStatus = intl.formatMessage(messages.creditPartialEligibleStatus, { creditLink }); break; default: break; @@ -106,8 +83,4 @@ const CreditInformation = ({ intl }) => { ); }; -CreditInformation.propTypes = { - intl: intlShape.isRequired, -}; - -export default injectIntl(CreditInformation); +export default CreditInformation; diff --git a/src/course-home/progress-tab/credit-information/messages.ts b/src/course-home/progress-tab/credit-information/messages.ts index 939f6ca4..93c3f195 100644 --- a/src/course-home/progress-tab/credit-information/messages.ts +++ b/src/course-home/progress-tab/credit-information/messages.ts @@ -35,6 +35,22 @@ const messages = defineMessages({ defaultMessage: 'Verification submitted', description: 'It indicate that the learner submitted a requirement but is not graded or reviewed yet', }, + creditNotEligibleStatus: { + id: 'progress.creditInformation.creditNotEligible', + defaultMessage: 'You are no longer eligible for credit in this course. Learn more about {creditLink}.', + description: 'Message to learner who are not eligible for course credit, it can be that a requirement deadline has passed', + }, + creditEligibleStatus: { + id: 'progress.creditInformation.creditEligible', + defaultMessage: `You have met the requirements for credit in this course. Go to your + {dashboardLink} to purchase course credit. Or learn more about {creditLink}.`, + description: 'After the credit requirements are met, leaners can then do the last step which purchasing the credit. Note that is only doable for leaners after they met all the requirements', + }, + creditPartialEligibleStatus: { + id: 'progress.creditInformation.creditPartialEligible', + defaultMessage: 'You have not yet met the requirements for credit. Learn more about {creditLink}.', + description: 'This means that one or more requirements is not satisfied yet', + }, }); export default messages; 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 c8dfb7e6..d69c6eee 100644 --- a/src/course-home/progress-tab/grades/course-grade/CourseGrade.jsx +++ b/src/course-home/progress-tab/grades/course-grade/CourseGrade.jsx @@ -1,5 +1,4 @@ -import React from 'react'; -import { injectIntl, intlShape } from '@edx/frontend-platform/i18n'; +import { useIntl } from '@edx/frontend-platform/i18n'; import { useContextId } from '../../../../data/hooks'; import { useModel } from '../../../../generic/model-store'; @@ -11,7 +10,8 @@ import CreditInformation from '../../credit-information/CreditInformation'; import messages from '../messages'; -const CourseGrade = ({ intl }) => { +const CourseGrade = () => { + const intl = useIntl(); const courseId = useContextId(); const { @@ -52,8 +52,4 @@ const CourseGrade = ({ intl }) => { ); }; -CourseGrade.propTypes = { - intl: intlShape.isRequired, -}; - -export default injectIntl(CourseGrade); +export default CourseGrade; diff --git a/src/course-home/progress-tab/grades/course-grade/CourseGradeFooter.jsx b/src/course-home/progress-tab/grades/course-grade/CourseGradeFooter.jsx index 650e3283..e075411f 100644 --- a/src/course-home/progress-tab/grades/course-grade/CourseGradeFooter.jsx +++ b/src/course-home/progress-tab/grades/course-grade/CourseGradeFooter.jsx @@ -1,7 +1,6 @@ -import React from 'react'; import PropTypes from 'prop-types'; -import { injectIntl, intlShape } from '@edx/frontend-platform/i18n'; +import { useIntl } from '@edx/frontend-platform/i18n'; import { CheckCircle, WarningFilled } from '@openedx/paragon/icons'; import { breakpoints, Icon, useWindowSize } from '@openedx/paragon'; import { useContextId } from '../../../../data/hooks'; @@ -10,7 +9,8 @@ import { useModel } from '../../../../generic/model-store'; import GradeRangeTooltip from './GradeRangeTooltip'; import messages from '../messages'; -const CourseGradeFooter = ({ intl, passingGrade }) => { +const CourseGradeFooter = ({ passingGrade }) => { + const intl = useIntl(); const courseId = useContextId(); const { @@ -84,8 +84,7 @@ const CourseGradeFooter = ({ intl, passingGrade }) => { }; CourseGradeFooter.propTypes = { - intl: intlShape.isRequired, passingGrade: PropTypes.number.isRequired, }; -export default injectIntl(CourseGradeFooter); +export default CourseGradeFooter; diff --git a/src/course-home/progress-tab/grades/course-grade/CourseGradeHeader.jsx b/src/course-home/progress-tab/grades/course-grade/CourseGradeHeader.jsx index 6349240e..87db4e73 100644 --- a/src/course-home/progress-tab/grades/course-grade/CourseGradeHeader.jsx +++ b/src/course-home/progress-tab/grades/course-grade/CourseGradeHeader.jsx @@ -1,8 +1,6 @@ -import React from 'react'; - import { sendTrackEvent } from '@edx/frontend-platform/analytics'; import { getAuthenticatedUser } from '@edx/frontend-platform/auth'; -import { injectIntl, intlShape } from '@edx/frontend-platform/i18n'; +import { useIntl } from '@edx/frontend-platform/i18n'; import { Locked } from '@openedx/paragon/icons'; import { Button, Icon } from '@openedx/paragon'; import { useContextId } from '../../../../data/hooks'; @@ -10,7 +8,8 @@ import { useContextId } from '../../../../data/hooks'; import { useModel } from '../../../../generic/model-store'; import messages from '../messages'; -const CourseGradeHeader = ({ intl }) => { +const CourseGradeHeader = () => { + const intl = useIntl(); const courseId = useContextId(); const { org, @@ -81,8 +80,4 @@ const CourseGradeHeader = ({ intl }) => { ); }; -CourseGradeHeader.propTypes = { - intl: intlShape.isRequired, -}; - -export default injectIntl(CourseGradeHeader); +export default CourseGradeHeader; diff --git a/src/course-home/progress-tab/grades/course-grade/CurrentGradeTooltip.jsx b/src/course-home/progress-tab/grades/course-grade/CurrentGradeTooltip.jsx index 3ea95785..36ba44e9 100644 --- a/src/course-home/progress-tab/grades/course-grade/CurrentGradeTooltip.jsx +++ b/src/course-home/progress-tab/grades/course-grade/CurrentGradeTooltip.jsx @@ -1,9 +1,6 @@ -import React from 'react'; import PropTypes from 'prop-types'; -import { - getLocale, injectIntl, intlShape, isRtl, -} from '@edx/frontend-platform/i18n'; +import { getLocale, isRtl, useIntl } from '@edx/frontend-platform/i18n'; import { OverlayTrigger, Popover } from '@openedx/paragon'; import { useContextId } from '../../../../data/hooks'; @@ -11,7 +8,8 @@ import { useModel } from '../../../../generic/model-store'; import messages from '../messages'; -const CurrentGradeTooltip = ({ intl, tooltipClassName }) => { +const CurrentGradeTooltip = ({ tooltipClassName }) => { + const intl = useIntl(); const courseId = useContextId(); const { @@ -67,8 +65,7 @@ CurrentGradeTooltip.defaultProps = { }; CurrentGradeTooltip.propTypes = { - intl: intlShape.isRequired, tooltipClassName: PropTypes.string, }; -export default injectIntl(CurrentGradeTooltip); +export default CurrentGradeTooltip; 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 98ed604e..bb45f366 100644 --- a/src/course-home/progress-tab/grades/course-grade/GradeBar.jsx +++ b/src/course-home/progress-tab/grades/course-grade/GradeBar.jsx @@ -1,9 +1,6 @@ -import React from 'react'; import PropTypes from 'prop-types'; -import { - getLocale, injectIntl, intlShape, isRtl, -} from '@edx/frontend-platform/i18n'; +import { getLocale, isRtl, useIntl } from '@edx/frontend-platform/i18n'; import { useContextId } from '../../../../data/hooks'; import { useModel } from '../../../../generic/model-store'; import CurrentGradeTooltip from './CurrentGradeTooltip'; @@ -11,7 +8,8 @@ import PassingGradeTooltip from './PassingGradeTooltip'; import messages from '../messages'; -const GradeBar = ({ intl, passingGrade }) => { +const GradeBar = ({ passingGrade }) => { + const intl = useIntl(); const courseId = useContextId(); const { @@ -50,8 +48,7 @@ const GradeBar = ({ intl, passingGrade }) => { }; GradeBar.propTypes = { - intl: intlShape.isRequired, passingGrade: PropTypes.number.isRequired, }; -export default injectIntl(GradeBar); +export default GradeBar; 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 c049cde7..9123b2cd 100644 --- a/src/course-home/progress-tab/grades/course-grade/GradeRangeTooltip.jsx +++ b/src/course-home/progress-tab/grades/course-grade/GradeRangeTooltip.jsx @@ -1,7 +1,7 @@ -import React, { useState } from 'react'; +import { useState } from 'react'; import PropTypes from 'prop-types'; -import { injectIntl, intlShape } from '@edx/frontend-platform/i18n'; +import { useIntl } from '@edx/frontend-platform/i18n'; import { InfoOutline } from '@openedx/paragon/icons'; import { Icon, IconButton, OverlayTrigger, Popover, @@ -11,7 +11,8 @@ import { useModel } from '../../../../generic/model-store'; import messages from '../messages'; -const GradeRangeTooltip = ({ intl, iconButtonClassName, passingGrade }) => { +const GradeRangeTooltip = ({ iconButtonClassName, passingGrade }) => { + const intl = useIntl(); const courseId = useContextId(); const { @@ -78,8 +79,7 @@ GradeRangeTooltip.defaultProps = { GradeRangeTooltip.propTypes = { iconButtonClassName: PropTypes.string, - intl: intlShape.isRequired, passingGrade: PropTypes.number.isRequired, }; -export default injectIntl(GradeRangeTooltip); +export default GradeRangeTooltip; diff --git a/src/course-home/progress-tab/grades/course-grade/PassingGradeTooltip.jsx b/src/course-home/progress-tab/grades/course-grade/PassingGradeTooltip.jsx index e315ab3a..4b77d28e 100644 --- a/src/course-home/progress-tab/grades/course-grade/PassingGradeTooltip.jsx +++ b/src/course-home/progress-tab/grades/course-grade/PassingGradeTooltip.jsx @@ -1,14 +1,12 @@ -import React from 'react'; import PropTypes from 'prop-types'; -import { - getLocale, injectIntl, intlShape, isRtl, -} from '@edx/frontend-platform/i18n'; +import { getLocale, isRtl, useIntl } from '@edx/frontend-platform/i18n'; import { OverlayTrigger, Popover } from '@openedx/paragon'; import messages from '../messages'; -const PassingGradeTooltip = ({ intl, passingGrade, tooltipClassName }) => { +const PassingGradeTooltip = ({ passingGrade, tooltipClassName }) => { + const intl = useIntl(); const isLocaleRtl = isRtl(getLocale()); let passingGradeDirection = passingGrade < 50 ? '' : '-'; @@ -54,9 +52,8 @@ PassingGradeTooltip.defaultProps = { }; PassingGradeTooltip.propTypes = { - intl: intlShape.isRequired, passingGrade: PropTypes.number.isRequired, tooltipClassName: PropTypes.string, }; -export default injectIntl(PassingGradeTooltip); +export default PassingGradeTooltip; 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 deb9dde2..6b618698 100644 --- a/src/course-home/progress-tab/grades/detailed-grades/DetailedGrades.jsx +++ b/src/course-home/progress-tab/grades/detailed-grades/DetailedGrades.jsx @@ -1,9 +1,7 @@ -import React from 'react'; - import { sendTrackEvent } from '@edx/frontend-platform/analytics'; import { getAuthenticatedUser } from '@edx/frontend-platform/auth'; -import { FormattedMessage, injectIntl, intlShape } from '@edx/frontend-platform/i18n'; -import { Blocked } from '@openedx/paragon/icons'; +import { useIntl } from '@edx/frontend-platform/i18n'; +import { Locked } from '@openedx/paragon/icons'; import { Icon, Hyperlink } from '@openedx/paragon'; import { useContextId } from '../../../../data/hooks'; import { useModel } from '../../../../generic/model-store'; @@ -13,7 +11,8 @@ import DetailedGradesTable from './DetailedGradesTable'; import messages from '../messages'; -const DetailedGrades = ({ intl }) => { +const DetailedGrades = () => { + const intl = useIntl(); const { administrator } = getAuthenticatedUser(); const courseId = useContextId(); const { @@ -59,25 +58,17 @@ const DetailedGrades = ({ intl }) => {
  • {intl.formatMessage(messages.practiceScoreLabel)} - + {intl.formatMessage(messages.practiceScoreInfoText)}
  • {intl.formatMessage(messages.gradedScoreLabel)} - + {intl.formatMessage(messages.gradedScoreInfoText)}
{gradesFeatureIsPartiallyLocked && (
- - {intl.formatMessage(messages.gradeSummaryLimitedAccessExplanation)} + + {intl.formatMessage(messages.gradeSummaryLimitedAccessExplanation, { upgradeLink: '' })}
)} {hasSectionScores && ( @@ -88,20 +79,11 @@ const DetailedGrades = ({ intl }) => { )} {overviewTabUrl && !showUngradedAssignments() && (

- + {intl.formatMessage(messages.ungradedAlert, { outlineLink })}

)} ); }; -DetailedGrades.propTypes = { - intl: intlShape.isRequired, -}; - -export default injectIntl(DetailedGrades); +export default DetailedGrades; 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 4b55e824..723aeae4 100644 --- a/src/course-home/progress-tab/grades/detailed-grades/DetailedGradesTable.jsx +++ b/src/course-home/progress-tab/grades/detailed-grades/DetailedGradesTable.jsx @@ -1,8 +1,4 @@ -import React from 'react'; - -import { - getLocale, injectIntl, intlShape, isRtl, -} from '@edx/frontend-platform/i18n'; +import { getLocale, isRtl, useIntl } from '@edx/frontend-platform/i18n'; import { DataTable } from '@openedx/paragon'; import { useContextId } from '../../../../data/hooks'; @@ -11,7 +7,8 @@ import messages from '../messages'; import SubsectionTitleCell from './SubsectionTitleCell'; import { showUngradedAssignments } from '../../utils'; -const DetailedGradesTable = ({ intl }) => { +const DetailedGradesTable = () => { + const intl = useIntl(); const courseId = useContextId(); const { @@ -66,8 +63,4 @@ const DetailedGradesTable = ({ intl }) => { ); }; -DetailedGradesTable.propTypes = { - intl: intlShape.isRequired, -}; - -export default injectIntl(DetailedGradesTable); +export default DetailedGradesTable; diff --git a/src/course-home/progress-tab/grades/detailed-grades/ProblemScoreDrawer.jsx b/src/course-home/progress-tab/grades/detailed-grades/ProblemScoreDrawer.jsx index 9088c39f..ead42754 100644 --- a/src/course-home/progress-tab/grades/detailed-grades/ProblemScoreDrawer.jsx +++ b/src/course-home/progress-tab/grades/detailed-grades/ProblemScoreDrawer.jsx @@ -1,14 +1,12 @@ -import React from 'react'; import PropTypes from 'prop-types'; import classNames from 'classnames'; -import { - getLocale, injectIntl, intlShape, isRtl, -} from '@edx/frontend-platform/i18n'; +import { getLocale, isRtl, useIntl } from '@edx/frontend-platform/i18n'; import messages from '../messages'; -const ProblemScoreDrawer = ({ intl, problemScores, subsection }) => { +const ProblemScoreDrawer = ({ problemScores, subsection }) => { + const intl = useIntl(); const isLocaleRtl = isRtl(getLocale()); const scoreLabel = subsection.hasGradedAssignment ? messages.gradedScoreLabel : messages.practiceScoreLabel; @@ -29,7 +27,6 @@ const ProblemScoreDrawer = ({ intl, problemScores, subsection }) => { }; ProblemScoreDrawer.propTypes = { - intl: intlShape.isRequired, problemScores: PropTypes.arrayOf(PropTypes.shape({ earned: PropTypes.number.isRequired, possible: PropTypes.number.isRequired, @@ -40,4 +37,4 @@ ProblemScoreDrawer.propTypes = { }).isRequired, }; -export default injectIntl(ProblemScoreDrawer); +export default ProblemScoreDrawer; diff --git a/src/course-home/progress-tab/grades/detailed-grades/SubsectionTitleCell.jsx b/src/course-home/progress-tab/grades/detailed-grades/SubsectionTitleCell.jsx index a1776456..3f856082 100644 --- a/src/course-home/progress-tab/grades/detailed-grades/SubsectionTitleCell.jsx +++ b/src/course-home/progress-tab/grades/detailed-grades/SubsectionTitleCell.jsx @@ -1,12 +1,14 @@ -import React from 'react'; import PropTypes from 'prop-types'; import { sendTrackEvent } from '@edx/frontend-platform/analytics'; import { getAuthenticatedUser } from '@edx/frontend-platform/auth'; -import { injectIntl, intlShape } from '@edx/frontend-platform/i18n'; +import { useIntl } from '@edx/frontend-platform/i18n'; import { Collapsible, Icon, Row } from '@openedx/paragon'; import { - ArrowDropDown, ArrowDropUp, Blocked, Info, + ArrowDropDown, + ArrowDropUp, + Info, + Locked, } from '@openedx/paragon/icons'; import { useContextId } from '../../../../data/hooks'; @@ -14,7 +16,8 @@ import messages from '../messages'; import { useModel } from '../../../../generic/model-store'; import ProblemScoreDrawer from './ProblemScoreDrawer'; -const SubsectionTitleCell = ({ intl, subsection }) => { +const SubsectionTitleCell = ({ subsection }) => { + const intl = useIntl(); const courseId = useContextId(); const { org, @@ -59,8 +62,8 @@ const SubsectionTitleCell = ({ intl, subsection }) => { aria-label={intl.formatMessage(messages.noAccessToSubsection, { displayName })} className="mr-1 mt-1 d-inline-flex" style={{ height: '1rem', width: '1rem' }} - src={Blocked} - data-testid="blocked-icon" + src={Locked} + data-testid="locked-icon" /> )} {url ? ( @@ -100,7 +103,6 @@ const SubsectionTitleCell = ({ intl, subsection }) => { }; SubsectionTitleCell.propTypes = { - intl: intlShape.isRequired, subsection: PropTypes.shape({ blockKey: PropTypes.string.isRequired, displayName: PropTypes.string.isRequired, @@ -117,4 +119,4 @@ SubsectionTitleCell.propTypes = { }).isRequired, }; -export default injectIntl(SubsectionTitleCell); +export default SubsectionTitleCell; 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 d0602af9..b84d07e2 100644 --- a/src/course-home/progress-tab/grades/grade-summary/AssignmentTypeCell.jsx +++ b/src/course-home/progress-tab/grades/grade-summary/AssignmentTypeCell.jsx @@ -1,22 +1,22 @@ -import React from 'react'; import PropTypes from 'prop-types'; -import { injectIntl, intlShape } from '@edx/frontend-platform/i18n'; -import { Blocked } from '@openedx/paragon/icons'; +import { useIntl } from '@edx/frontend-platform/i18n'; +import { Locked } from '@openedx/paragon/icons'; import { Icon } from '@openedx/paragon'; import { useContextId } from '../../../../data/hooks'; import { useModel } from '../../../../generic/model-store'; import messages from '../messages'; const AssignmentTypeCell = ({ - intl, assignmentType, footnoteMarker, footnoteId, locked, + assignmentType, footnoteMarker, footnoteId, locked, }) => { + const intl = useIntl(); const courseId = useContextId(); const { gradesFeatureIsFullyLocked, } = useModel('progress', courseId); - const lockedIcon = locked ? : ''; + const lockedIcon = locked ? : ''; return (
@@ -43,7 +43,6 @@ const AssignmentTypeCell = ({ }; AssignmentTypeCell.propTypes = { - intl: intlShape.isRequired, assignmentType: PropTypes.string.isRequired, footnoteId: PropTypes.string, footnoteMarker: PropTypes.number, @@ -56,4 +55,4 @@ AssignmentTypeCell.defaultProps = { locked: false, }; -export default injectIntl(AssignmentTypeCell); +export default AssignmentTypeCell; 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 92b78ebe..199fbb42 100644 --- a/src/course-home/progress-tab/grades/grade-summary/DroppableAssignmentFootnote.jsx +++ b/src/course-home/progress-tab/grades/grade-summary/DroppableAssignmentFootnote.jsx @@ -1,14 +1,13 @@ -import React from 'react'; - import PropTypes from 'prop-types'; -import { FormattedMessage, injectIntl, intlShape } from '@edx/frontend-platform/i18n'; +import { useIntl } from '@edx/frontend-platform/i18n'; import { useContextId } from '../../../../data/hooks'; import messages from '../messages'; import { useModel } from '../../../../generic/model-store'; -const DroppableAssignmentFootnote = ({ footnotes, intl }) => { +const DroppableAssignmentFootnote = ({ footnotes }) => { + const intl = useIntl(); const courseId = useContextId(); const { gradesFeatureIsFullyLocked, @@ -20,14 +19,10 @@ const DroppableAssignmentFootnote = ({ footnotes, intl }) => { {footnotes.map((footnote, index) => (
  • {index + 1} - + {intl.formatMessage(messages.droppableAssignmentsText, { + numDroppable: footnote.numDroppable, + assignmentType: footnote.assignmentType, + })} {intl.formatMessage(messages.backToContent)} @@ -44,7 +39,6 @@ DroppableAssignmentFootnote.propTypes = { id: PropTypes.string.isRequired, numDroppable: PropTypes.number.isRequired, })).isRequired, - intl: intlShape.isRequired, }; -export default injectIntl(DroppableAssignmentFootnote); +export default DroppableAssignmentFootnote; 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 aa4b788e..df1ff658 100644 --- a/src/course-home/progress-tab/grades/grade-summary/GradeSummaryHeader.jsx +++ b/src/course-home/progress-tab/grades/grade-summary/GradeSummaryHeader.jsx @@ -1,8 +1,13 @@ import PropTypes from 'prop-types'; - import { useIntl } from '@edx/frontend-platform/i18n'; -import { Icon, OverlayTrigger, Tooltip } from '@openedx/paragon'; -import { Blocked, InfoOutline } from '@openedx/paragon/icons'; +import { + Hyperlink, + Icon, + OverlayTrigger, + Stack, + Tooltip, +} from '@openedx/paragon'; +import { InfoOutline, Locked } from '@openedx/paragon/icons'; import { useContextId } from '../../../../data/hooks'; import messages from '../messages'; @@ -12,35 +17,48 @@ const GradeSummaryHeader = ({ allOfSomeAssignmentTypeIsLocked }) => { const intl = useIntl(); const courseId = useContextId(); const { + verifiedMode, gradesFeatureIsFullyLocked, } = useModel('progress', courseId); return ( -
    -

    {intl.formatMessage(messages.gradeSummary)}

    - - {intl.formatMessage(messages.gradeSummaryTooltipBody)} - - )} - > - - + + +

    {intl.formatMessage(messages.gradeSummary)}

    + + {intl.formatMessage(messages.gradeSummaryTooltipBody)} + + )} + > + + +
    {!gradesFeatureIsFullyLocked && allOfSomeAssignmentTypeIsLocked && ( -
    - - {intl.formatMessage(messages.gradeSummaryLimitedAccessExplanation)} -
    + + + + {intl.formatMessage( + messages.gradeSummaryLimitedAccessExplanation, + { + upgradeLink: verifiedMode && ( + + {intl.formatMessage(messages.courseGradePreviewUpgradeButton)}. + + ), + }, + )} + + )} -
    + ); }; diff --git a/src/course-home/progress-tab/grades/messages.ts b/src/course-home/progress-tab/grades/messages.ts index 24475b98..74030b1f 100644 --- a/src/course-home/progress-tab/grades/messages.ts +++ b/src/course-home/progress-tab/grades/messages.ts @@ -133,7 +133,7 @@ const messages = defineMessages({ }, gradeSummaryLimitedAccessExplanation: { id: 'progress.gradeSummary.limitedAccessExplanation', - defaultMessage: 'You have limited access to graded assignments as part of the audit track in this course.', + defaultMessage: 'You have limited access to graded assignments as part of the audit track in this course. {upgradeLink}', description: 'Text shown when learner has limited access to grade feature', }, gradeSummaryTooltipAlt: { @@ -208,6 +208,26 @@ const messages = defineMessages({ defaultMessage: 'Your raw weighted grade summary is {rawGrade} and rounds to {roundedGrade}.', description: 'Tooltip content that explains the rounding of the summary versus individual assignments', }, + practiceScoreInfoText: { + id: 'progress.detailedGrades.practice-label.info.text', + defaultMessage: 'Scores from non-graded activities meant for practice and self-assessment.', + description: 'Information text about non-graded practice score label', + }, + gradedScoreInfoText: { + id: 'progress.detailedGrades.problem-label.info.text', + defaultMessage: 'Scores from activities that contribute to your final grade.', + description: 'Information text about graded problem score label', + }, + ungradedAlert: { + id: 'progress.ungradedAlert', + defaultMessage: 'For progress on ungraded aspects of the course, view your {outlineLink}.', + description: 'Text that precede link that redirect to course outline page', + }, + droppableAssignmentsText: { + id: 'progress.footnotes.droppableAssignments', + defaultMessage: 'The lowest {numDroppable, plural, one{# {assignmentType} score is} other{# {assignmentType} scores are}} dropped.', + description: 'Footnote text stating how many assignments are dropped', + }, }); export default messages; diff --git a/src/course-home/progress-tab/related-links/RelatedLinks.jsx b/src/course-home/progress-tab/related-links/RelatedLinks.jsx index 0030f421..cf0c27db 100644 --- a/src/course-home/progress-tab/related-links/RelatedLinks.jsx +++ b/src/course-home/progress-tab/related-links/RelatedLinks.jsx @@ -1,15 +1,14 @@ -import React from 'react'; - import { sendTrackEvent } from '@edx/frontend-platform/analytics'; import { getAuthenticatedUser } from '@edx/frontend-platform/auth'; -import { injectIntl, intlShape } from '@edx/frontend-platform/i18n'; +import { useIntl } from '@edx/frontend-platform/i18n'; import { Hyperlink } from '@openedx/paragon'; import { useContextId } from '../../../data/hooks'; import messages from './messages'; import { useModel } from '../../../generic/model-store'; -const RelatedLinks = ({ intl }) => { +const RelatedLinks = () => { + const intl = useIntl(); const courseId = useContextId(); const { org, @@ -56,8 +55,4 @@ const RelatedLinks = ({ intl }) => { ); }; -RelatedLinks.propTypes = { - intl: intlShape.isRequired, -}; - -export default injectIntl(RelatedLinks); +export default RelatedLinks;