diff --git a/src/course-home/progress-tab/ProgressHeader.jsx b/src/course-home/progress-tab/ProgressHeader.jsx index 4648fd20ca..1d0fd56f8d 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 1b829037eb..a0d86a288b 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 ( <> @@ -39,18 +31,15 @@ const ProgressTab = () => { {/* Main body */}
{!disableProgressGraph && } - {!wideScreen && } - -
- - -
+ + +
{/* Side panel */}
- {wideScreen && } - + +
diff --git a/src/course-home/progress-tab/certificate-status/CertificateStatus.jsx b/src/course-home/progress-tab/certificate-status/CertificateStatus.jsx index 03837ee1c9..db237b0fc9 100644 --- a/src/course-home/progress-tab/certificate-status/CertificateStatus.jsx +++ b/src/course-home/progress-tab/certificate-status/CertificateStatus.jsx @@ -1,23 +1,23 @@ import React, { 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, injectIntl, intlShape, + 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'; import { requestCert } from '../../data/thunks'; import messages from './messages'; -const CertificateStatus = ({ intl }) => { - const { - courseId, - } = useSelector(state => state.courseHome); +const CertificateStatus = () => { + const intl = useIntl(); + const courseId = useContextId(); const { entranceExamData, @@ -267,8 +267,6 @@ const CertificateStatus = ({ intl }) => { ); }; -CertificateStatus.propTypes = { - intl: intlShape.isRequired, -}; +CertificateStatus.propTypes = {}; -export default injectIntl(CertificateStatus); +export default CertificateStatus; diff --git a/src/course-home/progress-tab/course-completion/CompletionDonutChart.jsx b/src/course-home/progress-tab/course-completion/CompletionDonutChart.jsx index 54b6caa9c6..8c008f0c48 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 f1bbcf6a1b..27843f9b0a 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 6aabdc08e6..c8dfb7e616 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 e662b13768..650e328356 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 4c4cfc7a16..6349240eb8 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 b869937045..3ea957858d 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 3cbbe5b1c0..98ed604e97 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 7489e73ae4..c049cde742 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 529859c52b..deb9dde2ab 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 f20bae3294..4b55e8249d 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 c3b3cb8bfe..a1776456e0 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 8de9fcedb4..d0602af9be 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 14f6b2c337..92b78ebe03 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 e6c6b9ad02..ffc5e2c890 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 fc860c10fa..3bd6fb4fb0 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); 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 628a65e24a..54e0388eeb 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 2c3235be86..18ad54d820 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 e7a6adf35e..0030f42139 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 0000000000..f8ad29bed8 --- /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(state => state.courseHome.courseId); diff --git a/src/index.jsx b/src/index.jsx index 6da653de6c..972d3c1ed2 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( - + diff --git a/src/plugin-slots/ProgressTabCertificateStatusMainBodySlot/README.md b/src/plugin-slots/ProgressTabCertificateStatusMainBodySlot/README.md new file mode 100644 index 0000000000..f2fe797ef3 --- /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 `

` element in a `

`. + +![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 ( +
+

📚: {courseId}

+
+ ); + }, + }, + }, + ] + } + }, +} + +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 0000000000..4f5858d4a9 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 0000000000..065d124949 --- /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 ( + + {!wideScreen && } + + ); +}; + +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 0000000000..83f73643db --- /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 `

` element in a `

`. + +![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 ( +
+

📚: {courseId}

+
+ ); + }, + }, + }, + ] + } + }, +} + +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 0000000000..4f5858d4a9 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 0000000000..2d84dcd907 --- /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 ( + + {wideScreen && } + + ); +}; + +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 0000000000..8c0d738132 --- /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 `

` element in a `

`. + +![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 ( +
+

📚: {courseId}

+
+ ); + }, + }, + }, + ] + } + }, +} + +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 0000000000..82a15f26bf 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 0000000000..fa4bf95693 --- /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 = () => ( + + + +); + +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 0000000000..85465e69c4 --- /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 `

` element in a `

`. + +![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 ( +
+

📚: {courseId}

+
+ ); + }, + }, + }, + ] + } + }, +} + +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 0000000000..03df7a4a87 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 0000000000..f54f1f7cee --- /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 ( + +
+ + +
+
+ ); +}; + +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 0000000000..32ea76109a --- /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 `

` element in a `

`. + +![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 ( +
+

📚: {courseId}

+
+ ); + }, + }, + }, + ] + } + }, +} + +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 0000000000..5ad62f9143 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 0000000000..c91dec1a86 --- /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 = () => ( + + + +); + +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 9343b0d24a..32a77cdafe 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;