`.
+
+![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 (
+
+ );
+ },
+ },
+ },
+ ]
+ }
+ },
+}
+
+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..563217fb0b
--- /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 (
+
+ {windowWidth && !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 (
+
+ );
+ },
+ },
+ },
+ ]
+ }
+ },
+}
+
+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..e8354c9f47
--- /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 (
+
+ {windowWidth && 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 (
+
+ );
+ },
+ },
+ },
+ ]
+ }
+ },
+}
+
+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 (
+
+ );
+ },
+ },
+ },
+ ]
+ }
+ },
+}
+
+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 (
+
+ );
+ },
+ },
+ },
+ ]
+ }
+ },
+}
+
+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
;