Skip to content

Commit

Permalink
feat: Add plugin slots for progress page components
Browse files Browse the repository at this point in the history
Adds a slot for different components in the progress tab to allow them to be
overridden with custom components.

# Conflicts:
#	src/course-home/progress-tab/certificate-status/CertificateStatus.jsx

diff --git a/src/course-home/progress-tab/ProgressHeader.jsx b/src/course-home/progress-tab/ProgressHeader.jsx
index 4648fd20..1d0fd56f 100644
--- a/src/course-home/progress-tab/ProgressHeader.jsx
+++ b/src/course-home/progress-tab/ProgressHeader.jsx
@@ -1,9 +1,9 @@
 import React from 'react';
-import { useSelector } from 'react-redux';

 import { getAuthenticatedUser } from '@edx/frontend-platform/auth';
 import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
 import { Button } from '@openedx/paragon';
+import { useSelector } from 'react-redux';

 import { useModel } from '../../generic/model-store';

diff --git a/src/course-home/progress-tab/ProgressTab.jsx b/src/course-home/progress-tab/ProgressTab.jsx
index 1b829037..a0d86a28 100644
--- a/src/course-home/progress-tab/ProgressTab.jsx
+++ b/src/course-home/progress-tab/ProgressTab.jsx
@@ -1,27 +1,20 @@
 import React from 'react';
-import { useSelector } from 'react-redux';
-import { breakpoints, useWindowSize } from '@openedx/paragon';
+import { useWindowSize } from '@openedx/paragon';
+import { useContextId } from '../../data/hooks';
+import ProgressTabCertificateStatusSidePanelSlot from '../../plugin-slots/ProgressTabCertificateStatusSidePanelSlot';

-import CertificateStatus from './certificate-status/CertificateStatus';
 import CourseCompletion from './course-completion/CourseCompletion';
-import CourseGrade from './grades/course-grade/CourseGrade';
-import DetailedGrades from './grades/detailed-grades/DetailedGrades';
-import GradeSummary from './grades/grade-summary/GradeSummary';
 import ProgressHeader from './ProgressHeader';
-import RelatedLinks from './related-links/RelatedLinks';

+import ProgressTabCertificateStatusMainBodySlot from '../../plugin-slots/ProgressTabCertificateStatusMainBodySlot';
+import ProgressTabCourseGradeSlot from '../../plugin-slots/ProgressTabCourseGradeSlot';
+import ProgressTabGradeBreakdownSlot from '../../plugin-slots/ProgressTabGradeBreakdownSlot';
+import ProgressTabRelatedLinksSlot from '../../plugin-slots/ProgressTabRelatedLinksSlot';
 import { useModel } from '../../generic/model-store';

 const ProgressTab = () => {
-  const {
-    courseId,
-  } = useSelector(state => state.courseHome);
-
-  const {
-    gradesFeatureIsFullyLocked, disableProgressGraph,
-  } = useModel('progress', courseId);
-
-  const applyLockedOverlay = gradesFeatureIsFullyLocked ? 'locked-overlay' : '';
+  const courseId = useContextId();
+  const { disableProgressGraph } = useModel('progress', courseId);

   const windowWidth = useWindowSize().width;
   if (windowWidth === undefined) {
@@ -31,7 +24,6 @@ const ProgressTab = () => {
     return null;
   }

-  const wideScreen = windowWidth >= breakpoints.large.minWidth;
   return (
     <>
       <ProgressHeader />
@@ -39,18 +31,15 @@ const ProgressTab = () => {
         {/* Main body */}
         <div className="col-12 col-md-8 p-0">
           {!disableProgressGraph && <CourseCompletion />}
-          {!wideScreen && <CertificateStatus />}
-          <CourseGrade />
-          <div className={`grades my-4 p-4 rounded raised-card ${applyLockedOverlay}`} aria-hidden={gradesFeatureIsFullyLocked}>
-            <GradeSummary />
-            <DetailedGrades />
-          </div>
+          <ProgressTabCertificateStatusMainBodySlot />
+          <ProgressTabCourseGradeSlot />
+          <ProgressTabGradeBreakdownSlot />
         </div>

         {/* Side panel */}
         <div className="col-12 col-md-4 p-0 px-md-4">
-          {wideScreen && <CertificateStatus />}
-          <RelatedLinks />
+          <ProgressTabCertificateStatusSidePanelSlot />
+          <ProgressTabRelatedLinksSlot />
         </div>
       </div>
     </>
diff --git a/src/course-home/progress-tab/certificate-status/CertificateStatus.jsx b/src/course-home/progress-tab/certificate-status/CertificateStatus.jsx
index 0d157184..a4ac7da7 100644
--- a/src/course-home/progress-tab/certificate-status/CertificateStatus.jsx
+++ b/src/course-home/progress-tab/certificate-status/CertificateStatus.jsx
@@ -1,11 +1,12 @@
 import { useEffect } from 'react';
-import { useDispatch, useSelector } from 'react-redux';
+import { useDispatch } from 'react-redux';
 import { sendTrackEvent } from '@edx/frontend-platform/analytics';
 import { getAuthenticatedUser } from '@edx/frontend-platform/auth';
 import { FormattedDate, FormattedMessage, useIntl } from '@edx/frontend-platform/i18n';

 import { Button, Card } from '@openedx/paragon';
 import { getConfig } from '@edx/frontend-platform';
+import { useContextId } from '../../../data/hooks';
 import { useModel } from '../../../generic/model-store';
 import { COURSE_EXIT_MODES, getCourseExitMode } from '../../../courseware/course/course-exit/utils';
 import { DashboardLink, IdVerificationSupportLink, ProfileLink } from '../../../shared/links';
@@ -15,9 +16,7 @@ import ProgressCertificateStatusSlot from '../../../plugin-slots/ProgressCertifi

 const CertificateStatus = () => {
   const intl = useIntl();
-  const {
-    courseId,
-  } = useSelector(state => state.courseHome);
+  const courseId = useContextId();

   const {
     entranceExamData,
diff --git a/src/course-home/progress-tab/course-completion/CompletionDonutChart.jsx b/src/course-home/progress-tab/course-completion/CompletionDonutChart.jsx
index 54b6caa9..8c008f0c 100644
--- a/src/course-home/progress-tab/course-completion/CompletionDonutChart.jsx
+++ b/src/course-home/progress-tab/course-completion/CompletionDonutChart.jsx
@@ -1,8 +1,8 @@
 import React from 'react';
-import { useSelector } from 'react-redux';
 import {
   getLocale, injectIntl, intlShape, isRtl,
 } from '@edx/frontend-platform/i18n';
+import { useContextId } from '../../../data/hooks';
 import { useModel } from '../../../generic/model-store';

 import CompleteDonutSegment from './CompleteDonutSegment';
@@ -11,9 +11,7 @@ import LockedDonutSegment from './LockedDonutSegment';
 import messages from './messages';

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

   const {
     completionSummary: {
diff --git a/src/course-home/progress-tab/credit-information/CreditInformation.jsx b/src/course-home/progress-tab/credit-information/CreditInformation.jsx
index f1bbcf6a..27843f9b 100644
--- a/src/course-home/progress-tab/credit-information/CreditInformation.jsx
+++ b/src/course-home/progress-tab/credit-information/CreditInformation.jsx
@@ -1,9 +1,9 @@
 import React from 'react';
-import { useSelector } from 'react-redux';
 import { getConfig } from '@edx/frontend-platform';
 import { FormattedMessage, injectIntl, intlShape } from '@edx/frontend-platform/i18n';
 import { CheckCircle, WarningFilled, WatchFilled } from '@openedx/paragon/icons';
 import { Hyperlink, Icon } from '@openedx/paragon';
+import { useContextId } from '../../../data/hooks';

 import { useModel } from '../../../generic/model-store';
 import { DashboardLink } from '../../../shared/links';
@@ -11,9 +11,7 @@ import { DashboardLink } from '../../../shared/links';
 import messages from './messages';

 const CreditInformation = ({ intl }) => {
-  const {
-    courseId,
-  } = useSelector(state => state.courseHome);
+  const courseId = useContextId();

   const {
     creditCourseRequirements,
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 6aabdc08..c8dfb7e6 100644
--- a/src/course-home/progress-tab/grades/course-grade/CourseGrade.jsx
+++ b/src/course-home/progress-tab/grades/course-grade/CourseGrade.jsx
@@ -1,6 +1,6 @@
 import React from 'react';
-import { useSelector } from 'react-redux';
 import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
+import { useContextId } from '../../../../data/hooks';

 import { useModel } from '../../../../generic/model-store';

@@ -12,9 +12,7 @@ import CreditInformation from '../../credit-information/CreditInformation';
 import messages from '../messages';

 const CourseGrade = ({ intl }) => {
-  const {
-    courseId,
-  } = useSelector(state => state.courseHome);
+  const courseId = useContextId();

   const {
     creditCourseRequirements,
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 e662b137..650e3283 100644
--- a/src/course-home/progress-tab/grades/course-grade/CourseGradeFooter.jsx
+++ b/src/course-home/progress-tab/grades/course-grade/CourseGradeFooter.jsx
@@ -1,19 +1,17 @@
 import React from 'react';
-import { useSelector } from 'react-redux';
 import PropTypes from 'prop-types';

 import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
 import { CheckCircle, WarningFilled } from '@openedx/paragon/icons';
 import { breakpoints, Icon, useWindowSize } from '@openedx/paragon';
+import { useContextId } from '../../../../data/hooks';
 import { useModel } from '../../../../generic/model-store';

 import GradeRangeTooltip from './GradeRangeTooltip';
 import messages from '../messages';

 const CourseGradeFooter = ({ intl, passingGrade }) => {
-  const {
-    courseId,
-  } = useSelector(state => state.courseHome);
+  const courseId = useContextId();

   const {
     courseGrade: {
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 4c4cfc7a..6349240e 100644
--- a/src/course-home/progress-tab/grades/course-grade/CourseGradeHeader.jsx
+++ b/src/course-home/progress-tab/grades/course-grade/CourseGradeHeader.jsx
@@ -1,19 +1,17 @@
 import React from 'react';
-import { useSelector } from 'react-redux';

 import { sendTrackEvent } from '@edx/frontend-platform/analytics';
 import { getAuthenticatedUser } from '@edx/frontend-platform/auth';
 import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
 import { Locked } from '@openedx/paragon/icons';
 import { Button, Icon } from '@openedx/paragon';
+import { useContextId } from '../../../../data/hooks';

 import { useModel } from '../../../../generic/model-store';
 import messages from '../messages';

 const CourseGradeHeader = ({ intl }) => {
-  const {
-    courseId,
-  } = useSelector(state => state.courseHome);
+  const courseId = useContextId();
   const {
     org,
   } = useModel('courseHomeMeta', courseId);
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 b8699370..3ea95785 100644
--- a/src/course-home/progress-tab/grades/course-grade/CurrentGradeTooltip.jsx
+++ b/src/course-home/progress-tab/grades/course-grade/CurrentGradeTooltip.jsx
@@ -1,20 +1,18 @@
 import React from 'react';
 import PropTypes from 'prop-types';
-import { useSelector } from 'react-redux';

 import {
   getLocale, injectIntl, intlShape, isRtl,
 } from '@edx/frontend-platform/i18n';
 import { OverlayTrigger, Popover } from '@openedx/paragon';
+import { useContextId } from '../../../../data/hooks';

 import { useModel } from '../../../../generic/model-store';

 import messages from '../messages';

 const CurrentGradeTooltip = ({ intl, tooltipClassName }) => {
-  const {
-    courseId,
-  } = useSelector(state => state.courseHome);
+  const courseId = useContextId();

   const {
     courseGrade: {
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 3cbbe5b1..98ed604e 100644
--- a/src/course-home/progress-tab/grades/course-grade/GradeBar.jsx
+++ b/src/course-home/progress-tab/grades/course-grade/GradeBar.jsx
@@ -1,10 +1,10 @@
 import React from 'react';
-import { useSelector } from 'react-redux';
 import PropTypes from 'prop-types';

 import {
   getLocale, injectIntl, intlShape, isRtl,
 } from '@edx/frontend-platform/i18n';
+import { useContextId } from '../../../../data/hooks';
 import { useModel } from '../../../../generic/model-store';
 import CurrentGradeTooltip from './CurrentGradeTooltip';
 import PassingGradeTooltip from './PassingGradeTooltip';
@@ -12,9 +12,7 @@ import PassingGradeTooltip from './PassingGradeTooltip';
 import messages from '../messages';

 const GradeBar = ({ intl, passingGrade }) => {
-  const {
-    courseId,
-  } = useSelector(state => state.courseHome);
+  const courseId = useContextId();

   const {
     courseGrade: {
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 7489e73a..c049cde7 100644
--- a/src/course-home/progress-tab/grades/course-grade/GradeRangeTooltip.jsx
+++ b/src/course-home/progress-tab/grades/course-grade/GradeRangeTooltip.jsx
@@ -1,5 +1,4 @@
 import React, { useState } from 'react';
-import { useSelector } from 'react-redux';
 import PropTypes from 'prop-types';

 import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
@@ -7,14 +6,13 @@ import { InfoOutline } from '@openedx/paragon/icons';
 import {
   Icon, IconButton, OverlayTrigger, Popover,
 } from '@openedx/paragon';
+import { useContextId } from '../../../../data/hooks';
 import { useModel } from '../../../../generic/model-store';

 import messages from '../messages';

 const GradeRangeTooltip = ({ intl, iconButtonClassName, passingGrade }) => {
-  const {
-    courseId,
-  } = useSelector(state => state.courseHome);
+  const courseId = useContextId();

   const {
     gradesFeatureIsFullyLocked,
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 529859c5..deb9dde2 100644
--- a/src/course-home/progress-tab/grades/detailed-grades/DetailedGrades.jsx
+++ b/src/course-home/progress-tab/grades/detailed-grades/DetailedGrades.jsx
@@ -1,11 +1,11 @@
 import React from 'react';
-import { useSelector } from 'react-redux';

 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 { Icon, Hyperlink } from '@openedx/paragon';
+import { useContextId } from '../../../../data/hooks';
 import { useModel } from '../../../../generic/model-store';
 import { showUngradedAssignments } from '../../utils';

@@ -15,9 +15,7 @@ import messages from '../messages';

 const DetailedGrades = ({ intl }) => {
   const { administrator } = getAuthenticatedUser();
-  const {
-    courseId,
-  } = useSelector(state => state.courseHome);
+  const courseId = useContextId();
   const {
     org,
     tabs,
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 f20bae32..4b55e824 100644
--- a/src/course-home/progress-tab/grades/detailed-grades/DetailedGradesTable.jsx
+++ b/src/course-home/progress-tab/grades/detailed-grades/DetailedGradesTable.jsx
@@ -1,10 +1,10 @@
 import React from 'react';
-import { useSelector } from 'react-redux';

 import {
   getLocale, injectIntl, intlShape, isRtl,
 } from '@edx/frontend-platform/i18n';
 import { DataTable } from '@openedx/paragon';
+import { useContextId } from '../../../../data/hooks';

 import { useModel } from '../../../../generic/model-store';
 import messages from '../messages';
@@ -12,9 +12,7 @@ import SubsectionTitleCell from './SubsectionTitleCell';
 import { showUngradedAssignments } from '../../utils';

 const DetailedGradesTable = ({ intl }) => {
-  const {
-    courseId,
-  } = useSelector(state => state.courseHome);
+  const courseId = useContextId();

   const {
     sectionScores,
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 c3b3cb8b..a1776456 100644
--- a/src/course-home/progress-tab/grades/detailed-grades/SubsectionTitleCell.jsx
+++ b/src/course-home/progress-tab/grades/detailed-grades/SubsectionTitleCell.jsx
@@ -1,5 +1,4 @@
 import React from 'react';
-import { useSelector } from 'react-redux';
 import PropTypes from 'prop-types';

 import { sendTrackEvent } from '@edx/frontend-platform/analytics';
@@ -9,15 +8,14 @@ import { Collapsible, Icon, Row } from '@openedx/paragon';
 import {
   ArrowDropDown, ArrowDropUp, Blocked, Info,
 } from '@openedx/paragon/icons';
+import { useContextId } from '../../../../data/hooks';

 import messages from '../messages';
 import { useModel } from '../../../../generic/model-store';
 import ProblemScoreDrawer from './ProblemScoreDrawer';

 const SubsectionTitleCell = ({ intl, subsection }) => {
-  const {
-    courseId,
-  } = useSelector(state => state.courseHome);
+  const courseId = useContextId();
   const {
     org,
   } = useModel('courseHomeMeta', courseId);
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 8de9fced..d0602af9 100644
--- a/src/course-home/progress-tab/grades/grade-summary/AssignmentTypeCell.jsx
+++ b/src/course-home/progress-tab/grades/grade-summary/AssignmentTypeCell.jsx
@@ -1,18 +1,16 @@
 import React from 'react';
-import { useSelector } from 'react-redux';
 import PropTypes from 'prop-types';
 import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
 import { Blocked } 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,
 }) => {
-  const {
-    courseId,
-  } = useSelector(state => state.courseHome);
+  const courseId = useContextId();

   const {
     gradesFeatureIsFullyLocked,
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 14f6b2c3..92b78ebe 100644
--- a/src/course-home/progress-tab/grades/grade-summary/DroppableAssignmentFootnote.jsx
+++ b/src/course-home/progress-tab/grades/grade-summary/DroppableAssignmentFootnote.jsx
@@ -1,16 +1,15 @@
 import React from 'react';
-import { useSelector } from 'react-redux';
+
 import PropTypes from 'prop-types';

 import { FormattedMessage, injectIntl, intlShape } 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 {
-    courseId,
-  } = useSelector(state => state.courseHome);
+  const courseId = useContextId();
   const {
     gradesFeatureIsFullyLocked,
   } = useModel('progress', courseId);
diff --git a/src/course-home/progress-tab/grades/grade-summary/GradeSummary.jsx b/src/course-home/progress-tab/grades/grade-summary/GradeSummary.jsx
index e6c6b9ad..ffc5e2c8 100644
--- a/src/course-home/progress-tab/grades/grade-summary/GradeSummary.jsx
+++ b/src/course-home/progress-tab/grades/grade-summary/GradeSummary.jsx
@@ -1,14 +1,13 @@
 import React, { useState } from 'react';
-import { useSelector } from 'react-redux';
+
+import { useContextId } from '../../../../data/hooks';
 import { useModel } from '../../../../generic/model-store';

 import GradeSummaryHeader from './GradeSummaryHeader';
 import GradeSummaryTable from './GradeSummaryTable';

 const GradeSummary = () => {
-  const {
-    courseId,
-  } = useSelector(state => state.courseHome);
+  const courseId = useContextId();

   const {
     gradingPolicy: {
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 fc860c10..6a91061f 100644
--- a/src/course-home/progress-tab/grades/grade-summary/GradeSummaryHeader.jsx
+++ b/src/course-home/progress-tab/grades/grade-summary/GradeSummaryHeader.jsx
@@ -1,5 +1,5 @@
 import React, { useState } from 'react';
-import { useSelector } from 'react-redux';
+
 import PropTypes from 'prop-types';

 import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
@@ -7,14 +7,13 @@ import {
   Icon, IconButton, OverlayTrigger, Popover,
 } from '@openedx/paragon';
 import { Blocked, InfoOutline } from '@openedx/paragon/icons';
+import { useContextId } from '../../../../data/hooks';

 import messages from '../messages';
 import { useModel } from '../../../../generic/model-store';

 const GradeSummaryHeader = ({ intl, allOfSomeAssignmentTypeIsLocked }) => {
-  const {
-    courseId,
-  } = useSelector(state => state.courseHome);
+  const courseId = useContextId();
   const {
     gradesFeatureIsFullyLocked,
   } = useModel('progress', courseId);
@@ -28,7 +27,7 @@ const GradeSummaryHeader = ({ intl, allOfSomeAssignmentTypeIsLocked }) => {
         placement="top"
         show={showTooltip}
         overlay={(
-          <Popover>
+          <Popover id="grade-summary-tooltip">
             <Popover.Content className="small text-dark-700">
               {intl.formatMessage(messages.gradeSummaryTooltipBody)}
             </Popover.Content>
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 628a65e2..54e0388e 100644
--- a/src/course-home/progress-tab/grades/grade-summary/GradeSummaryTable.jsx
+++ b/src/course-home/progress-tab/grades/grade-summary/GradeSummaryTable.jsx
@@ -1,11 +1,11 @@
 import React from 'react';
 import PropTypes from 'prop-types';
-import { useSelector } from 'react-redux';

 import {
   getLocale, injectIntl, intlShape, isRtl,
 } from '@edx/frontend-platform/i18n';
 import { DataTable } from '@openedx/paragon';
+import { useContextId } from '../../../../data/hooks';
 import { useModel } from '../../../../generic/model-store';

 import AssignmentTypeCell from './AssignmentTypeCell';
@@ -15,9 +15,7 @@ import GradeSummaryTableFooter from './GradeSummaryTableFooter';
 import messages from '../messages';

 const GradeSummaryTable = ({ intl, setAllOfSomeAssignmentTypeIsLocked }) => {
-  const {
-    courseId,
-  } = useSelector(state => state.courseHome);
+  const courseId = useContextId();

   const {
     gradingPolicy: {
diff --git a/src/course-home/progress-tab/grades/grade-summary/GradeSummaryTableFooter.jsx b/src/course-home/progress-tab/grades/grade-summary/GradeSummaryTableFooter.jsx
index 2c3235be..18ad54d8 100644
--- a/src/course-home/progress-tab/grades/grade-summary/GradeSummaryTableFooter.jsx
+++ b/src/course-home/progress-tab/grades/grade-summary/GradeSummaryTableFooter.jsx
@@ -1,18 +1,16 @@
 import React from 'react';
-import { useSelector } from 'react-redux';

 import {
   getLocale, injectIntl, intlShape, isRtl,
 } from '@edx/frontend-platform/i18n';
 import { DataTable } from '@openedx/paragon';
+import { useContextId } from '../../../../data/hooks';
 import { useModel } from '../../../../generic/model-store';

 import messages from '../messages';

 const GradeSummaryTableFooter = ({ intl }) => {
-  const {
-    courseId,
-  } = useSelector(state => state.courseHome);
+  const courseId = useContextId();

   const {
     courseGrade: {
diff --git a/src/course-home/progress-tab/related-links/RelatedLinks.jsx b/src/course-home/progress-tab/related-links/RelatedLinks.jsx
index e7a6adf3..0030f421 100644
--- a/src/course-home/progress-tab/related-links/RelatedLinks.jsx
+++ b/src/course-home/progress-tab/related-links/RelatedLinks.jsx
@@ -1,18 +1,16 @@
 import React from 'react';
-import { useSelector } from 'react-redux';

 import { sendTrackEvent } from '@edx/frontend-platform/analytics';
 import { getAuthenticatedUser } from '@edx/frontend-platform/auth';
 import { injectIntl, intlShape } 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 {
-    courseId,
-  } = useSelector(state => state.courseHome);
+  const courseId = useContextId();
   const {
     org,
     tabs,
diff --git a/src/data/hooks.ts b/src/data/hooks.ts
new file mode 100644
index 00000000..f8ad29be
--- /dev/null
+++ b/src/data/hooks.ts
@@ -0,0 +1,5 @@
+import { useSelector } from 'react-redux';
+import { RootState } from '../store';
+
+// eslint-disable-next-line import/prefer-default-export
+export const useContextId = () => useSelector<RootState>(state => state.courseHome.courseId);
diff --git a/src/index.jsx b/src/index.jsx
index 6da653de..972d3c1e 100755
--- a/src/index.jsx
+++ b/src/index.jsx
@@ -26,7 +26,7 @@ import { TabContainer } from './tab-page';

 import { fetchDatesTab, fetchOutlineTab, fetchProgressTab } from './course-home/data';
 import { fetchCourse } from './courseware/data';
-import initializeStore from './store';
+import { store } from './store';
 import NoticesProvider from './generic/notices';
 import PathFixesProvider from './generic/path-fixes';
 import LiveTab from './course-home/live-tab/LiveTab';
@@ -38,7 +38,7 @@ import PageNotFound from './generic/PageNotFound';

 subscribe(APP_READY, () => {
   ReactDOM.render(
-    <AppProvider store={initializeStore()}>
+    <AppProvider store={store}>
       <Helmet>
         <link rel="shortcut icon" href={getConfig().FAVICON_URL} type="image/x-icon" />
       </Helmet>
diff --git a/src/plugin-slots/ProgressTabCertificateStatusMainBodySlot/README.md b/src/plugin-slots/ProgressTabCertificateStatusMainBodySlot/README.md
new file mode 100644
index 00000000..f2fe797e
--- /dev/null
+++ b/src/plugin-slots/ProgressTabCertificateStatusMainBodySlot/README.md
@@ -0,0 +1,47 @@
+# Progress Tab Certificate Status Slot
+
+### Slot ID: `progress_tab_certificate_status_main_body_slot`
+### Props:
+
+## Description
+
+This slot is used to replace or modify the Certificate Status component in the
+main body of the Progress Tab.
+
+## Example
+
+The following `env.config.jsx` will render the `course_id` of the course as a `<p>` element in a `<div>`.
+
+![Screenshot of Content added after the Certificate Status Container](./images/progress_tab_certificate_status_slot.png)
+
+```js
+import { DIRECT_PLUGIN, PLUGIN_OPERATIONS } from '@openedx/frontend-plugin-framework';
+import { useContextId } from './src/data/hooks';
+
+const config = {
+  pluginSlots: {
+    progress_tab_certificate_status_main_body_slot: {
+      plugins: [
+        {
+          // Insert custom content after certificate status
+          op: PLUGIN_OPERATIONS.Insert,
+          widget: {
+            id: 'custom_certificate_status_content',
+            type: DIRECT_PLUGIN,
+            RenderWidget: () => {
+              const courseId = useContextId();
+              return (
+                <div>
+                  <p>📚: {courseId}</p>
+                </div>
+              );
+            },
+          },
+        },
+      ]
+    }
+  },
+}
+
+export default config;
+```
diff --git a/src/plugin-slots/ProgressTabCertificateStatusMainBodySlot/images/progress_tab_certificate_status_slot.png b/src/plugin-slots/ProgressTabCertificateStatusMainBodySlot/images/progress_tab_certificate_status_slot.png
new file mode 100644
index 00000000..4f5858d4
Binary files /dev/null and b/src/plugin-slots/ProgressTabCertificateStatusMainBodySlot/images/progress_tab_certificate_status_slot.png differ
diff --git a/src/plugin-slots/ProgressTabCertificateStatusMainBodySlot/index.jsx b/src/plugin-slots/ProgressTabCertificateStatusMainBodySlot/index.jsx
new file mode 100644
index 00000000..563217fb
--- /dev/null
+++ b/src/plugin-slots/ProgressTabCertificateStatusMainBodySlot/index.jsx
@@ -0,0 +1,19 @@
+import { PluginSlot } from '@openedx/frontend-plugin-framework';
+import { breakpoints, useWindowSize } from '@openedx/paragon';
+import CertificateStatus from '../../course-home/progress-tab/certificate-status/CertificateStatus';
+
+const ProgressTabCertificateStatusMainBodySlot = () => {
+  const windowWidth = useWindowSize().width;
+  const wideScreen = windowWidth >= breakpoints.large.minWidth;
+  return (
+    <PluginSlot
+      id="progress_tab_certificate_status_main_body_slot"
+    >
+      {windowWidth && !wideScreen && <CertificateStatus />}
+    </PluginSlot>
+  );
+};
+
+ProgressTabCertificateStatusMainBodySlot.propTypes = {};
+
+export default ProgressTabCertificateStatusMainBodySlot;
diff --git a/src/plugin-slots/ProgressTabCertificateStatusSidePanelSlot/README.md b/src/plugin-slots/ProgressTabCertificateStatusSidePanelSlot/README.md
new file mode 100644
index 00000000..83f73643
--- /dev/null
+++ b/src/plugin-slots/ProgressTabCertificateStatusSidePanelSlot/README.md
@@ -0,0 +1,47 @@
+# Progress Tab Certificate Status Slot
+
+### Slot ID: `progress_tab_certificate_status_side_panel_slot`
+### Props:
+
+## Description
+
+This slot is used to replace or modify the Certificate Status component in the
+side panel of the Progress Tab.
+
+## Example
+
+The following `env.config.jsx` will render the `course_id` of the course as a `<p>` element in a `<div>`.
+
+![Screenshot of Content added after the Certificate Status Container](./images/progress_tab_certificate_status_slot.png)
+
+```js
+import { DIRECT_PLUGIN, PLUGIN_OPERATIONS } from '@openedx/frontend-plugin-framework';
+import { useContextId } from './src/data/hooks';
+
+const config = {
+  pluginSlots: {
+    progress_tab_certificate_status_side_panel_slot: {
+      plugins: [
+        {
+          // Insert custom content after certificate status
+          op: PLUGIN_OPERATIONS.Insert,
+          widget: {
+            id: 'custom_certificate_status_content',
+            type: DIRECT_PLUGIN,
+            RenderWidget: () => {
+              const courseId = useContextId();
+              return (
+                <div>
+                  <p>📚: {courseId}</p>
+                </div>
+              );
+            },
+          },
+        },
+      ]
+    }
+  },
+}
+
+export default config;
+```
diff --git a/src/plugin-slots/ProgressTabCertificateStatusSidePanelSlot/images/progress_tab_certificate_status_slot.png b/src/plugin-slots/ProgressTabCertificateStatusSidePanelSlot/images/progress_tab_certificate_status_slot.png
new file mode 100644
index 00000000..4f5858d4
Binary files /dev/null and b/src/plugin-slots/ProgressTabCertificateStatusSidePanelSlot/images/progress_tab_certificate_status_slot.png differ
diff --git a/src/plugin-slots/ProgressTabCertificateStatusSidePanelSlot/index.jsx b/src/plugin-slots/ProgressTabCertificateStatusSidePanelSlot/index.jsx
new file mode 100644
index 00000000..e8354c9f
--- /dev/null
+++ b/src/plugin-slots/ProgressTabCertificateStatusSidePanelSlot/index.jsx
@@ -0,0 +1,19 @@
+import { PluginSlot } from '@openedx/frontend-plugin-framework';
+import { breakpoints, useWindowSize } from '@openedx/paragon';
+import CertificateStatus from '../../course-home/progress-tab/certificate-status/CertificateStatus';
+
+const ProgressTabCertificateStatusSidePanelSlot = () => {
+  const windowWidth = useWindowSize().width;
+  const wideScreen = windowWidth >= breakpoints.large.minWidth;
+  return (
+    <PluginSlot
+      id="progress_tab_certificate_status_side_panel_slot"
+    >
+      {windowWidth && wideScreen && <CertificateStatus />}
+    </PluginSlot>
+  );
+};
+
+ProgressTabCertificateStatusSidePanelSlot.propTypes = {};
+
+export default ProgressTabCertificateStatusSidePanelSlot;
diff --git a/src/plugin-slots/ProgressTabCourseGradeSlot/README.md b/src/plugin-slots/ProgressTabCourseGradeSlot/README.md
new file mode 100644
index 00000000..8c0d7381
--- /dev/null
+++ b/src/plugin-slots/ProgressTabCourseGradeSlot/README.md
@@ -0,0 +1,46 @@
+# Progress Tab Course Grade Slot
+
+### Slot ID: `progress_tab_course_grade_slot`
+### Props:
+
+## Description
+
+This slot is used to replace or modify the Course Grades view in the Progress Tab.
+
+## Example
+
+The following `env.config.jsx` will render the `course_id` of the course as a `<p>` element in a `<div>`.
+
+![Screenshot of Content added after the Grades Container](./images/progress_tab_course_grade_slot.png)
+
+```js
+import { DIRECT_PLUGIN, PLUGIN_OPERATIONS } from '@openedx/frontend-plugin-framework';
+import { useContextId } from './src/data/hooks';
+
+const config = {
+  pluginSlots: {
+    progress_tab_course_grade_slot: {
+      plugins: [
+        {
+          // Insert custom content after course grade widget
+          op: PLUGIN_OPERATIONS.Insert,
+          widget: {
+            id: 'custom_course_grade_content',
+            type: DIRECT_PLUGIN,
+            RenderWidget: () => {
+              const courseId = useContextId();
+              return (
+                <div>
+                  <p>📚: {courseId}</p>
+                </div>
+              );
+            },
+          },
+        },
+      ]
+    }
+  },
+}
+
+export default config;
+```
diff --git a/src/plugin-slots/ProgressTabCourseGradeSlot/images/progress_tab_course_grade_slot.png b/src/plugin-slots/ProgressTabCourseGradeSlot/images/progress_tab_course_grade_slot.png
new file mode 100644
index 00000000..82a15f26
Binary files /dev/null and b/src/plugin-slots/ProgressTabCourseGradeSlot/images/progress_tab_course_grade_slot.png differ
diff --git a/src/plugin-slots/ProgressTabCourseGradeSlot/index.jsx b/src/plugin-slots/ProgressTabCourseGradeSlot/index.jsx
new file mode 100644
index 00000000..fa4bf956
--- /dev/null
+++ b/src/plugin-slots/ProgressTabCourseGradeSlot/index.jsx
@@ -0,0 +1,14 @@
+import { PluginSlot } from '@openedx/frontend-plugin-framework';
+import CourseGrade from '../../course-home/progress-tab/grades/course-grade/CourseGrade';
+
+const ProgressTabCourseGradeSlot = () => (
+  <PluginSlot
+    id="progress_tab_course_grade_slot"
+  >
+    <CourseGrade />
+  </PluginSlot>
+);
+
+ProgressTabCourseGradeSlot.propTypes = {};
+
+export default ProgressTabCourseGradeSlot;
diff --git a/src/plugin-slots/ProgressTabGradeBreakdownSlot/README.md b/src/plugin-slots/ProgressTabGradeBreakdownSlot/README.md
new file mode 100644
index 00000000..85465e69
--- /dev/null
+++ b/src/plugin-slots/ProgressTabGradeBreakdownSlot/README.md
@@ -0,0 +1,46 @@
+# Progress Tab Grade Breakdown Slot
+
+### Slot ID: `progress_tab_grade_breakdown_slot`
+### Props:
+
+## Description
+
+This slot is used to replace or modify the Grade Summary and Details Breakdown view in the Progress Tab.
+
+## Example
+
+The following `env.config.jsx` will render the `course_id` of the course as a `<p>` element in a `<div>`.
+
+![Screenshot of Content added after the Grade Summary and Details Container](./images/progress_tab_grade_breakdown_slot.png)
+
+```js
+import { DIRECT_PLUGIN, PLUGIN_OPERATIONS } from '@openedx/frontend-plugin-framework';
+import { useContextId } from './src/data/hooks';
+
+const config = {
+  pluginSlots: {
+    progress_tab_grade_breakdown_slot: {
+      plugins: [
+        {
+          // Insert custom content after grade summary widget
+          op: PLUGIN_OPERATIONS.Insert,
+          widget: {
+            id: 'custom_grade_summary_content',
+            type: DIRECT_PLUGIN,
+            RenderWidget: () => {
+              const courseId = useContextId();
+              return (
+                <div>
+                  <p>📚: {courseId}</p>
+                </div>
+              );
+            },
+          },
+        },
+      ]
+    }
+  },
+}
+
+export default config;
+```
diff --git a/src/plugin-slots/ProgressTabGradeBreakdownSlot/images/progress_tab_grade_breakdown_slot.png b/src/plugin-slots/ProgressTabGradeBreakdownSlot/images/progress_tab_grade_breakdown_slot.png
new file mode 100644
index 00000000..03df7a4a
Binary files /dev/null and b/src/plugin-slots/ProgressTabGradeBreakdownSlot/images/progress_tab_grade_breakdown_slot.png differ
diff --git a/src/plugin-slots/ProgressTabGradeBreakdownSlot/index.jsx b/src/plugin-slots/ProgressTabGradeBreakdownSlot/index.jsx
new file mode 100644
index 00000000..f54f1f7c
--- /dev/null
+++ b/src/plugin-slots/ProgressTabGradeBreakdownSlot/index.jsx
@@ -0,0 +1,29 @@
+import { useModel } from '@src/generic/model-store';
+import { PluginSlot } from '@openedx/frontend-plugin-framework';
+import React from 'react';
+import DetailedGrades from '../../course-home/progress-tab/grades/detailed-grades/DetailedGrades';
+import GradeSummary from '../../course-home/progress-tab/grades/grade-summary/GradeSummary';
+import { useContextId } from '../../data/hooks';
+
+const ProgressTabGradeBreakdownSlot = () => {
+  const courseId = useContextId();
+  const { gradesFeatureIsFullyLocked } = useModel('progress', courseId);
+  const applyLockedOverlay = gradesFeatureIsFullyLocked ? 'locked-overlay' : '';
+  return (
+    <PluginSlot
+      id="progress_tab_grade_breakdown_slot"
+    >
+      <div
+        className={`grades my-4 p-4 rounded raised-card ${applyLockedOverlay}`}
+        aria-hidden={gradesFeatureIsFullyLocked}
+      >
+        <GradeSummary />
+        <DetailedGrades />
+      </div>
+    </PluginSlot>
+  );
+};
+
+ProgressTabGradeBreakdownSlot.propTypes = {};
+
+export default ProgressTabGradeBreakdownSlot;
diff --git a/src/plugin-slots/ProgressTabRelatedLinksSlot/README.md b/src/plugin-slots/ProgressTabRelatedLinksSlot/README.md
new file mode 100644
index 00000000..32ea7610
--- /dev/null
+++ b/src/plugin-slots/ProgressTabRelatedLinksSlot/README.md
@@ -0,0 +1,46 @@
+# Progress Tab Related Links Slot
+
+### Slot ID: `progress_tab_related_links_slot`
+### Props:
+
+## Description
+
+This slot is used to replace or modify the related links view in the Progress Tab.
+
+## Example
+
+The following `env.config.jsx` will render the `course_id` of the course as a `<p>` element in a `<div>`.
+
+![Screenshot of Content added after the Related Links Container](./images/progress_tab_related_links_slot.png)
+
+```js
+import { DIRECT_PLUGIN, PLUGIN_OPERATIONS } from '@openedx/frontend-plugin-framework';
+import { useContextId } from './src/data/hooks';
+
+const config = {
+  pluginSlots: {
+    progress_tab_related_links_slot: {
+      plugins: [
+        {
+          // Insert custom content after related links widget
+          op: PLUGIN_OPERATIONS.Insert,
+          widget: {
+            id: 'custom_related_links_content',
+            type: DIRECT_PLUGIN,
+            RenderWidget: () => {
+              const courseId = useContextId();
+              return (
+                <div>
+                  <p>📚: {courseId}</p>
+                </div>
+              );
+            },
+          },
+        },
+      ]
+    }
+  },
+}
+
+export default config;
+```
diff --git a/src/plugin-slots/ProgressTabRelatedLinksSlot/images/progress_tab_related_links_slot.png b/src/plugin-slots/ProgressTabRelatedLinksSlot/images/progress_tab_related_links_slot.png
new file mode 100644
index 00000000..5ad62f91
Binary files /dev/null and b/src/plugin-slots/ProgressTabRelatedLinksSlot/images/progress_tab_related_links_slot.png differ
diff --git a/src/plugin-slots/ProgressTabRelatedLinksSlot/index.jsx b/src/plugin-slots/ProgressTabRelatedLinksSlot/index.jsx
new file mode 100644
index 00000000..c91dec1a
--- /dev/null
+++ b/src/plugin-slots/ProgressTabRelatedLinksSlot/index.jsx
@@ -0,0 +1,14 @@
+import { PluginSlot } from '@openedx/frontend-plugin-framework';
+import RelatedLinks from '../../course-home/progress-tab/related-links/RelatedLinks';
+
+const ProgressTabRelatedLinksSlot = () => (
+  <PluginSlot
+    id="progress_tab_related_links_slot"
+  >
+    <RelatedLinks />
+  </PluginSlot>
+);
+
+ProgressTabRelatedLinksSlot.propTypes = {};
+
+export default ProgressTabRelatedLinksSlot;
diff --git a/src/store.js b/src/store.ts
similarity index 92%
rename from src/store.js
rename to src/store.ts
index 9343b0d2..32a77cda 100644
--- a/src/store.js
+++ b/src/store.ts
@@ -29,3 +29,7 @@ export default function initializeStore() {
     }),
   });
 }
+
+export const store = initializeStore();
+
+export type RootState = ReturnType<typeof store.getState>;
  • Loading branch information
xitij2000 committed Dec 19, 2024
1 parent 4a80532 commit 1f04104
Show file tree
Hide file tree
Showing 39 changed files with 396 additions and 105 deletions.
2 changes: 1 addition & 1 deletion src/course-home/progress-tab/ProgressHeader.jsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,9 @@
import React from 'react';
import { useSelector } from 'react-redux';

import { getAuthenticatedUser } from '@edx/frontend-platform/auth';
import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
import { Button } from '@openedx/paragon';
import { useSelector } from 'react-redux';

import { useModel } from '../../generic/model-store';

Expand Down
39 changes: 14 additions & 25 deletions src/course-home/progress-tab/ProgressTab.jsx
Original file line number Diff line number Diff line change
@@ -1,27 +1,20 @@
import React from 'react';
import { useSelector } from 'react-redux';
import { breakpoints, useWindowSize } from '@openedx/paragon';
import { useWindowSize } from '@openedx/paragon';
import { useContextId } from '../../data/hooks';
import ProgressTabCertificateStatusSidePanelSlot from '../../plugin-slots/ProgressTabCertificateStatusSidePanelSlot';

import CertificateStatus from './certificate-status/CertificateStatus';
import CourseCompletion from './course-completion/CourseCompletion';
import CourseGrade from './grades/course-grade/CourseGrade';
import DetailedGrades from './grades/detailed-grades/DetailedGrades';
import GradeSummary from './grades/grade-summary/GradeSummary';
import ProgressHeader from './ProgressHeader';
import RelatedLinks from './related-links/RelatedLinks';

import ProgressTabCertificateStatusMainBodySlot from '../../plugin-slots/ProgressTabCertificateStatusMainBodySlot';
import ProgressTabCourseGradeSlot from '../../plugin-slots/ProgressTabCourseGradeSlot';
import ProgressTabGradeBreakdownSlot from '../../plugin-slots/ProgressTabGradeBreakdownSlot';
import ProgressTabRelatedLinksSlot from '../../plugin-slots/ProgressTabRelatedLinksSlot';
import { useModel } from '../../generic/model-store';

const ProgressTab = () => {
const {
courseId,
} = useSelector(state => state.courseHome);

const {
gradesFeatureIsFullyLocked, disableProgressGraph,
} = useModel('progress', courseId);

const applyLockedOverlay = gradesFeatureIsFullyLocked ? 'locked-overlay' : '';
const courseId = useContextId();
const { disableProgressGraph } = useModel('progress', courseId);

const windowWidth = useWindowSize().width;
if (windowWidth === undefined) {
Expand All @@ -31,26 +24,22 @@ const ProgressTab = () => {
return null;
}

const wideScreen = windowWidth >= breakpoints.large.minWidth;
return (
<>
<ProgressHeader />
<div className="row w-100 m-0">
{/* Main body */}
<div className="col-12 col-md-8 p-0">
{!disableProgressGraph && <CourseCompletion />}
{!wideScreen && <CertificateStatus />}
<CourseGrade />
<div className={`grades my-4 p-4 rounded raised-card ${applyLockedOverlay}`} aria-hidden={gradesFeatureIsFullyLocked}>
<GradeSummary />
<DetailedGrades />
</div>
<ProgressTabCertificateStatusMainBodySlot />
<ProgressTabCourseGradeSlot />
<ProgressTabGradeBreakdownSlot />
</div>

{/* Side panel */}
<div className="col-12 col-md-4 p-0 px-md-4">
{wideScreen && <CertificateStatus />}
<RelatedLinks />
<ProgressTabCertificateStatusSidePanelSlot />
<ProgressTabRelatedLinksSlot />
</div>
</div>
</>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,12 @@
import { useEffect } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { useDispatch } from 'react-redux';
import { sendTrackEvent } from '@edx/frontend-platform/analytics';
import { getAuthenticatedUser } from '@edx/frontend-platform/auth';
import { FormattedDate, FormattedMessage, useIntl } from '@edx/frontend-platform/i18n';

import { Button, Card } from '@openedx/paragon';
import { getConfig } from '@edx/frontend-platform';
import { useContextId } from '../../../data/hooks';
import { useModel } from '../../../generic/model-store';
import { COURSE_EXIT_MODES, getCourseExitMode } from '../../../courseware/course/course-exit/utils';
import { DashboardLink, IdVerificationSupportLink, ProfileLink } from '../../../shared/links';
Expand All @@ -15,9 +16,7 @@ import ProgressCertificateStatusSlot from '../../../plugin-slots/ProgressCertifi

const CertificateStatus = () => {
const intl = useIntl();
const {
courseId,
} = useSelector(state => state.courseHome);
const courseId = useContextId();

const {
entranceExamData,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import React from 'react';
import { useSelector } from 'react-redux';
import {
getLocale, injectIntl, intlShape, isRtl,
} from '@edx/frontend-platform/i18n';
import { useContextId } from '../../../data/hooks';
import { useModel } from '../../../generic/model-store';

import CompleteDonutSegment from './CompleteDonutSegment';
Expand All @@ -11,9 +11,7 @@ import LockedDonutSegment from './LockedDonutSegment';
import messages from './messages';

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

const {
completionSummary: {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,19 +1,17 @@
import React from 'react';
import { useSelector } from 'react-redux';
import { getConfig } from '@edx/frontend-platform';
import { FormattedMessage, injectIntl, intlShape } from '@edx/frontend-platform/i18n';
import { CheckCircle, WarningFilled, WatchFilled } from '@openedx/paragon/icons';
import { Hyperlink, Icon } from '@openedx/paragon';
import { useContextId } from '../../../data/hooks';

import { useModel } from '../../../generic/model-store';
import { DashboardLink } from '../../../shared/links';

import messages from './messages';

const CreditInformation = ({ intl }) => {
const {
courseId,
} = useSelector(state => state.courseHome);
const courseId = useContextId();

const {
creditCourseRequirements,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import React from 'react';
import { useSelector } from 'react-redux';
import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
import { useContextId } from '../../../../data/hooks';

import { useModel } from '../../../../generic/model-store';

Expand All @@ -12,9 +12,7 @@ import CreditInformation from '../../credit-information/CreditInformation';
import messages from '../messages';

const CourseGrade = ({ intl }) => {
const {
courseId,
} = useSelector(state => state.courseHome);
const courseId = useContextId();

const {
creditCourseRequirements,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,19 +1,17 @@
import React from 'react';
import { useSelector } from 'react-redux';
import PropTypes from 'prop-types';

import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
import { CheckCircle, WarningFilled } from '@openedx/paragon/icons';
import { breakpoints, Icon, useWindowSize } from '@openedx/paragon';
import { useContextId } from '../../../../data/hooks';
import { useModel } from '../../../../generic/model-store';

import GradeRangeTooltip from './GradeRangeTooltip';
import messages from '../messages';

const CourseGradeFooter = ({ intl, passingGrade }) => {
const {
courseId,
} = useSelector(state => state.courseHome);
const courseId = useContextId();

const {
courseGrade: {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,19 +1,17 @@
import React from 'react';
import { useSelector } from 'react-redux';

import { sendTrackEvent } from '@edx/frontend-platform/analytics';
import { getAuthenticatedUser } from '@edx/frontend-platform/auth';
import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
import { Locked } from '@openedx/paragon/icons';
import { Button, Icon } from '@openedx/paragon';
import { useContextId } from '../../../../data/hooks';

import { useModel } from '../../../../generic/model-store';
import messages from '../messages';

const CourseGradeHeader = ({ intl }) => {
const {
courseId,
} = useSelector(state => state.courseHome);
const courseId = useContextId();
const {
org,
} = useModel('courseHomeMeta', courseId);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,20 +1,18 @@
import React from 'react';
import PropTypes from 'prop-types';
import { useSelector } from 'react-redux';

import {
getLocale, injectIntl, intlShape, isRtl,
} from '@edx/frontend-platform/i18n';
import { OverlayTrigger, Popover } from '@openedx/paragon';
import { useContextId } from '../../../../data/hooks';

import { useModel } from '../../../../generic/model-store';

import messages from '../messages';

const CurrentGradeTooltip = ({ intl, tooltipClassName }) => {
const {
courseId,
} = useSelector(state => state.courseHome);
const courseId = useContextId();

const {
courseGrade: {
Expand Down
6 changes: 2 additions & 4 deletions src/course-home/progress-tab/grades/course-grade/GradeBar.jsx
Original file line number Diff line number Diff line change
@@ -1,20 +1,18 @@
import React from 'react';
import { useSelector } from 'react-redux';
import PropTypes from 'prop-types';

import {
getLocale, injectIntl, intlShape, isRtl,
} from '@edx/frontend-platform/i18n';
import { useContextId } from '../../../../data/hooks';
import { useModel } from '../../../../generic/model-store';
import CurrentGradeTooltip from './CurrentGradeTooltip';
import PassingGradeTooltip from './PassingGradeTooltip';

import messages from '../messages';

const GradeBar = ({ intl, passingGrade }) => {
const {
courseId,
} = useSelector(state => state.courseHome);
const courseId = useContextId();

const {
courseGrade: {
Expand Down
Original file line number Diff line number Diff line change
@@ -1,20 +1,18 @@
import React, { useState } from 'react';
import { useSelector } from 'react-redux';
import PropTypes from 'prop-types';

import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
import { InfoOutline } from '@openedx/paragon/icons';
import {
Icon, IconButton, OverlayTrigger, Popover,
} from '@openedx/paragon';
import { useContextId } from '../../../../data/hooks';
import { useModel } from '../../../../generic/model-store';

import messages from '../messages';

const GradeRangeTooltip = ({ intl, iconButtonClassName, passingGrade }) => {
const {
courseId,
} = useSelector(state => state.courseHome);
const courseId = useContextId();

const {
gradesFeatureIsFullyLocked,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
import React from 'react';
import { useSelector } from 'react-redux';

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 { Icon, Hyperlink } from '@openedx/paragon';
import { useContextId } from '../../../../data/hooks';
import { useModel } from '../../../../generic/model-store';
import { showUngradedAssignments } from '../../utils';

Expand All @@ -15,9 +15,7 @@ import messages from '../messages';

const DetailedGrades = ({ intl }) => {
const { administrator } = getAuthenticatedUser();
const {
courseId,
} = useSelector(state => state.courseHome);
const courseId = useContextId();
const {
org,
tabs,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,20 +1,18 @@
import React from 'react';
import { useSelector } from 'react-redux';

import {
getLocale, injectIntl, intlShape, isRtl,
} from '@edx/frontend-platform/i18n';
import { DataTable } from '@openedx/paragon';
import { useContextId } from '../../../../data/hooks';

import { useModel } from '../../../../generic/model-store';
import messages from '../messages';
import SubsectionTitleCell from './SubsectionTitleCell';
import { showUngradedAssignments } from '../../utils';

const DetailedGradesTable = ({ intl }) => {
const {
courseId,
} = useSelector(state => state.courseHome);
const courseId = useContextId();

const {
sectionScores,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import React from 'react';
import { useSelector } from 'react-redux';
import PropTypes from 'prop-types';

import { sendTrackEvent } from '@edx/frontend-platform/analytics';
Expand All @@ -9,15 +8,14 @@ import { Collapsible, Icon, Row } from '@openedx/paragon';
import {
ArrowDropDown, ArrowDropUp, Blocked, Info,
} from '@openedx/paragon/icons';
import { useContextId } from '../../../../data/hooks';

import messages from '../messages';
import { useModel } from '../../../../generic/model-store';
import ProblemScoreDrawer from './ProblemScoreDrawer';

const SubsectionTitleCell = ({ intl, subsection }) => {
const {
courseId,
} = useSelector(state => state.courseHome);
const courseId = useContextId();
const {
org,
} = useModel('courseHomeMeta', courseId);
Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,16 @@
import React from 'react';
import { useSelector } from 'react-redux';
import PropTypes from 'prop-types';
import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
import { Blocked } 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,
}) => {
const {
courseId,
} = useSelector(state => state.courseHome);
const courseId = useContextId();

const {
gradesFeatureIsFullyLocked,
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,15 @@
import React from 'react';
import { useSelector } from 'react-redux';

import PropTypes from 'prop-types';

import { FormattedMessage, injectIntl, intlShape } 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 {
courseId,
} = useSelector(state => state.courseHome);
const courseId = useContextId();
const {
gradesFeatureIsFullyLocked,
} = useModel('progress', courseId);
Expand Down
Loading

0 comments on commit 1f04104

Please sign in to comment.