From 83b51f697e5f201422249fb205bb588bb68cc9bc Mon Sep 17 00:00:00 2001 From: Jansen Kantor Date: Thu, 20 Mar 2025 16:32:23 -0400 Subject: [PATCH 1/9] feat: add additional course end plugin slots --- .../course/course-exit/CourseCelebration.jsx | 17 ++++-- .../course/course-exit/CourseExit.jsx | 17 ++---- .../course/course-exit/DashboardFootnote.jsx | 36 ++----------- src/courseware/course/course-exit/messages.ts | 5 ++ .../CourseExitViewCoursesPluginSlot/README.md | 37 +++++++++++++ .../CourseExitViewCoursesPluginSlot/index.jsx | 39 ++++++++++++++ .../CourseRecommendationsSlot/README.md | 0 .../CourseRecommendationsSlot/index.jsx | 2 +- .../screenshot_custom.png | Bin .../DashboardFootnoteLinkPluginSlot/README.md | 40 ++++++++++++++ .../DashboardFootnoteLinkPluginSlot/index.jsx | 50 ++++++++++++++++++ .../CourseExitPluginSlots/index.jsx | 9 ++++ 12 files changed, 201 insertions(+), 51 deletions(-) create mode 100644 src/plugin-slots/CourseExitPluginSlots/CourseExitViewCoursesPluginSlot/README.md create mode 100644 src/plugin-slots/CourseExitPluginSlots/CourseExitViewCoursesPluginSlot/index.jsx rename src/plugin-slots/{ => CourseExitPluginSlots}/CourseRecommendationsSlot/README.md (100%) rename src/plugin-slots/{ => CourseExitPluginSlots}/CourseRecommendationsSlot/index.jsx (83%) rename src/plugin-slots/{ => CourseExitPluginSlots}/CourseRecommendationsSlot/screenshot_custom.png (100%) create mode 100644 src/plugin-slots/CourseExitPluginSlots/DashboardFootnoteLinkPluginSlot/README.md create mode 100644 src/plugin-slots/CourseExitPluginSlots/DashboardFootnoteLinkPluginSlot/index.jsx create mode 100644 src/plugin-slots/CourseExitPluginSlots/index.jsx diff --git a/src/courseware/course/course-exit/CourseCelebration.jsx b/src/courseware/course/course-exit/CourseCelebration.jsx index d4193954b2..02ba94ac67 100644 --- a/src/courseware/course/course-exit/CourseCelebration.jsx +++ b/src/courseware/course/course-exit/CourseCelebration.jsx @@ -25,12 +25,12 @@ import messages from './messages'; import { useModel } from '../../../generic/model-store'; import { requestCert } from '../../../course-home/data/thunks'; import ProgramCompletion from './ProgramCompletion'; -import DashboardFootnote from './DashboardFootnote'; import UpgradeFootnote from './UpgradeFootnote'; import SocialIcons from '../../social-share/SocialIcons'; import { logClick, logVisit } from './utils'; import { DashboardLink, IdVerificationSupportLink, ProfileLink } from '../../../shared/links'; -import CourseRecommendationsSlot from '../../../plugin-slots/CourseRecommendationsSlot'; +import DashboardFootnote from './DashboardFootnote'; +import { CourseRecommendationsSlot } from '../../../plugin-slots/CourseExitPluginSlots'; const LINKEDIN_BLUE = '#2867B2'; @@ -53,11 +53,20 @@ const CourseCelebration = () => { const { org, - verifiedMode, + // verifiedMode, canViewCertificate, userTimezone, } = useModel('courseHomeMeta', courseId); + const verifiedMode = { + accessExpirationDate: null, + currency: 'USD', + currencySymbol: '$', + price: 99, + sku: '765F6C2', + upgradeUrl: 'https://commerce-coordinator.edx.org/lms/payment_page_redirect/?sku=765F6C2&course_run_key=course-v1%3AIBM%2BPY0101EN%2B2T2023', + }; + const { certStatus, certWebViewUrl, @@ -83,7 +92,7 @@ const CourseCelebration = () => { let certHeader; let visitEvent = 'celebration_generic'; // These cases are taken from the edx-platform `get_cert_data` function found in lms/courseware/views/views.py - switch (certStatus) { + switch ('audit_passing') { case 'downloadable': certHeader = intl.formatMessage(messages.certificateHeaderDownloadable); message = ( diff --git a/src/courseware/course/course-exit/CourseExit.jsx b/src/courseware/course/course-exit/CourseExit.jsx index 60d57200ac..385e8021ec 100644 --- a/src/courseware/course/course-exit/CourseExit.jsx +++ b/src/courseware/course/course-exit/CourseExit.jsx @@ -1,8 +1,5 @@ -import React, { useEffect } from 'react'; +import { useEffect } from 'react'; -import { getConfig } from '@edx/frontend-platform'; -import { useIntl } from '@edx/frontend-platform/i18n'; -import { Button } from '@openedx/paragon'; import { useSelector } from 'react-redux'; import { Navigate } from 'react-router-dom'; @@ -10,13 +7,12 @@ import CourseCelebration from './CourseCelebration'; import CourseInProgress from './CourseInProgress'; import CourseNonPassing from './CourseNonPassing'; import { COURSE_EXIT_MODES, getCourseExitMode } from './utils'; -import messages from './messages'; import { unsubscribeFromGoalReminders } from './data/thunks'; +import { CourseExitViewCoursesPluginSlot } from '../../../plugin-slots/CourseExitPluginSlots'; import { useModel } from '../../../generic/model-store'; const CourseExit = () => { - const intl = useIntl(); const { courseId } = useSelector(state => state.courseware); const { certificateData, @@ -64,14 +60,7 @@ const CourseExit = () => { return ( <> -
- -
+ {body} ); diff --git a/src/courseware/course/course-exit/DashboardFootnote.jsx b/src/courseware/course/course-exit/DashboardFootnote.jsx index 7ac7a4405f..7edbd12acb 100644 --- a/src/courseware/course/course-exit/DashboardFootnote.jsx +++ b/src/courseware/course/course-exit/DashboardFootnote.jsx @@ -1,47 +1,19 @@ -import React from 'react'; import PropTypes from 'prop-types'; -import { useSelector } from 'react-redux'; - -import { getAuthenticatedUser } from '@edx/frontend-platform/auth'; -import { FormattedMessage, useIntl } from '@edx/frontend-platform/i18n'; -import { Hyperlink } from '@openedx/paragon'; +import { useIntl } from '@edx/frontend-platform/i18n'; import { faCalendarAlt } from '@fortawesome/free-regular-svg-icons'; -import { getConfig } from '@edx/frontend-platform'; - -import { useModel } from '../../../generic/model-store'; +import { DashboardFootnoteLinkPluginSlot } from '../../../plugin-slots/CourseExitPluginSlots'; import Footnote from './Footnote'; import messages from './messages'; -import { logClick } from './utils'; const DashboardFootnote = ({ variant }) => { const intl = useIntl(); - const { courseId } = useSelector(state => state.courseware); - const { org } = useModel('courseHomeMeta', courseId); - const { administrator } = getAuthenticatedUser(); - - const dashboardLink = ( - logClick(org, courseId, administrator, 'dashboard_footnote', { variant })} - > - {intl.formatMessage(messages.dashboardLink)} - - ); + const dashboardLink = (); return ( - )} + text={intl.formatMessage(messages.dashboardInfo, { dashboardLink })} /> ); }; diff --git a/src/courseware/course/course-exit/messages.ts b/src/courseware/course/course-exit/messages.ts index 297596fef2..0c0d1ff10a 100644 --- a/src/courseware/course/course-exit/messages.ts +++ b/src/courseware/course/course-exit/messages.ts @@ -76,6 +76,11 @@ const messages = defineMessages({ defaultMessage: 'Dashboard', description: 'Link to user’s dashboard', }, + dashboardInfo: { + id: 'courseCelebration.dashboardInfo', // for historical reasons + defaultMessage: 'You can access this course and its materials on your {dashboardLink}.', + description: "Text that precedes link to learner's dashboard", + }, endOfCourseDescription: { id: 'courseExit.endOfCourseDescription', defaultMessage: 'Unfortunately, you are not currently eligible for a certificate. You need to receive a passing grade to be eligible for a certificate.', diff --git a/src/plugin-slots/CourseExitPluginSlots/CourseExitViewCoursesPluginSlot/README.md b/src/plugin-slots/CourseExitPluginSlots/CourseExitViewCoursesPluginSlot/README.md new file mode 100644 index 0000000000..a4c9160077 --- /dev/null +++ b/src/plugin-slots/CourseExitPluginSlots/CourseExitViewCoursesPluginSlot/README.md @@ -0,0 +1,37 @@ +# Course Exit "View Courses" Button Plugin Slot + +### Slot ID: `course_exit_view_courses_slot` +### Props: +* `href` + +## Description + +This slot is used for modifying "View Courses" button in the course exit screen + +## Example + +The following `env.config.jsx` will make the link link to `example.com` + +```js +import { DIRECT_PLUGIN, PLUGIN_OPERATIONS } from '@openedx/frontend-plugin-framework'; + +const config = { + pluginSlots: { + course_exit_view_courses_slot: { + keepDefault: true, + plugins: [ + { + op: PLUGIN_OPERATIONS.Modify, + widgetId: 'default_contents', + fn: (widget) => { + widget.content.href = 'http://www.example.com'; + return widget; + } + }, + ] + }, + }, +} + +export default config; +``` diff --git a/src/plugin-slots/CourseExitPluginSlots/CourseExitViewCoursesPluginSlot/index.jsx b/src/plugin-slots/CourseExitPluginSlots/CourseExitViewCoursesPluginSlot/index.jsx new file mode 100644 index 0000000000..080580e8ae --- /dev/null +++ b/src/plugin-slots/CourseExitPluginSlots/CourseExitViewCoursesPluginSlot/index.jsx @@ -0,0 +1,39 @@ +import { Button } from '@openedx/paragon'; +import PropTypes from 'prop-types'; +import { getConfig } from '@edx/frontend-platform'; +import { PluginSlot } from '@openedx/frontend-plugin-framework'; +import { useIntl } from '@edx/frontend-platform/i18n'; +import messages from '../../../courseware/course/course-exit/messages'; + +const ViewCoursesLink = ({ content }) => { + const intl = useIntl(); + return ( +
+ +
+ ); +}; + +ViewCoursesLink.propTypes = { + content: PropTypes.shape({ + href: PropTypes.string.isRequired, + }).isRequired, +}; + +const CourseExitViewCoursesPluginSlot = () => { + const href = `${getConfig().LMS_BASE_URL}/dashboard`; + return ( + + + + ); +}; + +CourseExitViewCoursesPluginSlot.propTypes = {}; + +export default CourseExitViewCoursesPluginSlot; diff --git a/src/plugin-slots/CourseRecommendationsSlot/README.md b/src/plugin-slots/CourseExitPluginSlots/CourseRecommendationsSlot/README.md similarity index 100% rename from src/plugin-slots/CourseRecommendationsSlot/README.md rename to src/plugin-slots/CourseExitPluginSlots/CourseRecommendationsSlot/README.md diff --git a/src/plugin-slots/CourseRecommendationsSlot/index.jsx b/src/plugin-slots/CourseExitPluginSlots/CourseRecommendationsSlot/index.jsx similarity index 83% rename from src/plugin-slots/CourseRecommendationsSlot/index.jsx rename to src/plugin-slots/CourseExitPluginSlots/CourseRecommendationsSlot/index.jsx index c286ba51a0..4e222a832a 100644 --- a/src/plugin-slots/CourseRecommendationsSlot/index.jsx +++ b/src/plugin-slots/CourseExitPluginSlots/CourseRecommendationsSlot/index.jsx @@ -1,6 +1,6 @@ import PropTypes from 'prop-types'; import { PluginSlot } from '@openedx/frontend-plugin-framework'; -import CourseRecommendations from '../../courseware/course/course-exit/CourseRecommendations'; +import CourseRecommendations from '../../../courseware/course/course-exit/CourseRecommendations'; const CourseRecommendationsSlot = ({ variant }) => ( { + widget.content.destination = 'http://www.example.com'; + return widget; + } + }, + ] + }, + }, +} + +export default config; +``` diff --git a/src/plugin-slots/CourseExitPluginSlots/DashboardFootnoteLinkPluginSlot/index.jsx b/src/plugin-slots/CourseExitPluginSlots/DashboardFootnoteLinkPluginSlot/index.jsx new file mode 100644 index 0000000000..3f8b2917b3 --- /dev/null +++ b/src/plugin-slots/CourseExitPluginSlots/DashboardFootnoteLinkPluginSlot/index.jsx @@ -0,0 +1,50 @@ +import PropTypes from 'prop-types'; +import { Hyperlink } from '@openedx/paragon'; +import { getConfig } from '@edx/frontend-platform'; +import { PluginSlot } from '@openedx/frontend-plugin-framework'; +import { useIntl } from '@edx/frontend-platform/i18n'; +import { useSelector } from 'react-redux'; +import { getAuthenticatedUser } from '@edx/frontend-platform/auth'; +import messages from '../../../courseware/course/course-exit/messages'; +import { logClick } from '../../../courseware/course/course-exit/utils'; +import { useModel } from '../../../generic/model-store'; + +const DashboardFootnoteLink = ({ variant, content }) => { + const intl = useIntl(); + const { courseId } = useSelector(state => state.courseware); + const { org } = useModel('courseHomeMeta', courseId); + const { administrator } = getAuthenticatedUser(); + const { destination } = content; + return ( + logClick(org, courseId, administrator, 'dashboard_footnote', { variant })} + > + {intl.formatMessage(messages.dashboardLink)} + + ); +}; + +DashboardFootnoteLink.propTypes = { + variant: PropTypes.string.isRequired, + content: PropTypes.shape({ + destination: PropTypes.string.isRequired, + }).isRequired, +}; + +const DashboardFootnoteLinkPluginSlot = ({ variant }) => { + const destination = `${getConfig().LMS_BASE_URL}/dashboard`; + return ( + + + + ); +}; + +DashboardFootnoteLinkPluginSlot.propTypes = { + variant: PropTypes.string.isRequired, +}; + +export default DashboardFootnoteLinkPluginSlot; diff --git a/src/plugin-slots/CourseExitPluginSlots/index.jsx b/src/plugin-slots/CourseExitPluginSlots/index.jsx new file mode 100644 index 0000000000..2e65103b0e --- /dev/null +++ b/src/plugin-slots/CourseExitPluginSlots/index.jsx @@ -0,0 +1,9 @@ +import DashboardFootnoteLinkPluginSlot from './DashboardFootnoteLinkPluginSlot'; +import CourseRecommendationsSlot from './CourseRecommendationsSlot'; +import CourseExitViewCoursesPluginSlot from './CourseExitViewCoursesPluginSlot'; + +export { + DashboardFootnoteLinkPluginSlot, + CourseRecommendationsSlot, + CourseExitViewCoursesPluginSlot, +}; From 7bd0aa44932cf411e17b0c7ac755f053462c7952 Mon Sep 17 00:00:00 2001 From: Jansen Kantor Date: Thu, 24 Apr 2025 14:53:41 -0400 Subject: [PATCH 2/9] fix: bring plugin slot names in line with new naming scheme --- .../CourseExitViewCoursesPluginSlot/README.md | 6 +++--- .../CourseExitViewCoursesPluginSlot/index.jsx | 2 +- .../DashboardFootnoteLinkPluginSlot/README.md | 4 ++-- .../DashboardFootnoteLinkPluginSlot/index.jsx | 2 +- 4 files changed, 7 insertions(+), 7 deletions(-) diff --git a/src/plugin-slots/CourseExitPluginSlots/CourseExitViewCoursesPluginSlot/README.md b/src/plugin-slots/CourseExitPluginSlots/CourseExitViewCoursesPluginSlot/README.md index a4c9160077..fb283eb9ce 100644 --- a/src/plugin-slots/CourseExitPluginSlots/CourseExitViewCoursesPluginSlot/README.md +++ b/src/plugin-slots/CourseExitPluginSlots/CourseExitViewCoursesPluginSlot/README.md @@ -1,8 +1,8 @@ # Course Exit "View Courses" Button Plugin Slot -### Slot ID: `course_exit_view_courses_slot` +### Slot ID: `org.openedx.frontend.learning.course_exit_view_courses.v1` ### Props: -* `href` +* `content: { href }` ## Description @@ -17,7 +17,7 @@ import { DIRECT_PLUGIN, PLUGIN_OPERATIONS } from '@openedx/frontend-plugin-frame const config = { pluginSlots: { - course_exit_view_courses_slot: { + 'org.openedx.frontend.learning.course_exit_view_courses.v1: { keepDefault: true, plugins: [ { diff --git a/src/plugin-slots/CourseExitPluginSlots/CourseExitViewCoursesPluginSlot/index.jsx b/src/plugin-slots/CourseExitPluginSlots/CourseExitViewCoursesPluginSlot/index.jsx index 080580e8ae..6281cfd5c6 100644 --- a/src/plugin-slots/CourseExitPluginSlots/CourseExitViewCoursesPluginSlot/index.jsx +++ b/src/plugin-slots/CourseExitPluginSlots/CourseExitViewCoursesPluginSlot/index.jsx @@ -28,7 +28,7 @@ ViewCoursesLink.propTypes = { const CourseExitViewCoursesPluginSlot = () => { const href = `${getConfig().LMS_BASE_URL}/dashboard`; return ( - + ); diff --git a/src/plugin-slots/CourseExitPluginSlots/DashboardFootnoteLinkPluginSlot/README.md b/src/plugin-slots/CourseExitPluginSlots/DashboardFootnoteLinkPluginSlot/README.md index 4998b1260c..67aab098ee 100644 --- a/src/plugin-slots/CourseExitPluginSlots/DashboardFootnoteLinkPluginSlot/README.md +++ b/src/plugin-slots/CourseExitPluginSlots/DashboardFootnoteLinkPluginSlot/README.md @@ -1,6 +1,6 @@ # Course Exit Dashboard Footnote Link Plugin Slot -### Slot ID: `course_exit_dashboard_footnote_link_slot` +### Slot ID: `org.openedx.frontend.learning.course_exit_dashboard_footnote_link.v1` ### Props: * `variant` * `content: { destination }` @@ -20,7 +20,7 @@ import { DIRECT_PLUGIN, PLUGIN_OPERATIONS } from '@openedx/frontend-plugin-frame const config = { pluginSlots: { - course_exit_dashboard_footnote_link_slot: { + 'org.openedx.frontend.learning.course_exit_dashboard_footnote_link.v1': { keepDefault: true, plugins: [ { diff --git a/src/plugin-slots/CourseExitPluginSlots/DashboardFootnoteLinkPluginSlot/index.jsx b/src/plugin-slots/CourseExitPluginSlots/DashboardFootnoteLinkPluginSlot/index.jsx index 3f8b2917b3..bab443151b 100644 --- a/src/plugin-slots/CourseExitPluginSlots/DashboardFootnoteLinkPluginSlot/index.jsx +++ b/src/plugin-slots/CourseExitPluginSlots/DashboardFootnoteLinkPluginSlot/index.jsx @@ -37,7 +37,7 @@ DashboardFootnoteLink.propTypes = { const DashboardFootnoteLinkPluginSlot = ({ variant }) => { const destination = `${getConfig().LMS_BASE_URL}/dashboard`; return ( - + ); From 50d716a8f59894f9daf4e742522b7340439feea6 Mon Sep 17 00:00:00 2001 From: Jansen Kantor Date: Thu, 24 Apr 2025 15:06:46 -0400 Subject: [PATCH 3/9] refactor: change plugin files to tsx,remove propTypes --- .../{index.jsx => index.tsx} | 16 +++++-------- .../{index.jsx => index.tsx} | 11 ++++----- .../{index.jsx => index.tsx} | 24 ++++++++----------- 3 files changed, 21 insertions(+), 30 deletions(-) rename src/plugin-slots/CourseExitPluginSlots/CourseExitViewCoursesPluginSlot/{index.jsx => index.tsx} (77%) rename src/plugin-slots/CourseExitPluginSlots/CourseRecommendationsSlot/{index.jsx => index.tsx} (69%) rename src/plugin-slots/CourseExitPluginSlots/DashboardFootnoteLinkPluginSlot/{index.jsx => index.tsx} (76%) diff --git a/src/plugin-slots/CourseExitPluginSlots/CourseExitViewCoursesPluginSlot/index.jsx b/src/plugin-slots/CourseExitPluginSlots/CourseExitViewCoursesPluginSlot/index.tsx similarity index 77% rename from src/plugin-slots/CourseExitPluginSlots/CourseExitViewCoursesPluginSlot/index.jsx rename to src/plugin-slots/CourseExitPluginSlots/CourseExitViewCoursesPluginSlot/index.tsx index 6281cfd5c6..a876722a0f 100644 --- a/src/plugin-slots/CourseExitPluginSlots/CourseExitViewCoursesPluginSlot/index.jsx +++ b/src/plugin-slots/CourseExitPluginSlots/CourseExitViewCoursesPluginSlot/index.tsx @@ -5,7 +5,11 @@ import { PluginSlot } from '@openedx/frontend-plugin-framework'; import { useIntl } from '@edx/frontend-platform/i18n'; import messages from '../../../courseware/course/course-exit/messages'; -const ViewCoursesLink = ({ content }) => { +interface Props { + content: { href: string } +} + +const ViewCoursesLink: React.FC = ({ content }) => { const intl = useIntl(); return (
@@ -19,13 +23,7 @@ const ViewCoursesLink = ({ content }) => { ); }; -ViewCoursesLink.propTypes = { - content: PropTypes.shape({ - href: PropTypes.string.isRequired, - }).isRequired, -}; - -const CourseExitViewCoursesPluginSlot = () => { +const CourseExitViewCoursesPluginSlot: React.FC = () => { const href = `${getConfig().LMS_BASE_URL}/dashboard`; return ( @@ -34,6 +32,4 @@ const CourseExitViewCoursesPluginSlot = () => { ); }; -CourseExitViewCoursesPluginSlot.propTypes = {}; - export default CourseExitViewCoursesPluginSlot; diff --git a/src/plugin-slots/CourseExitPluginSlots/CourseRecommendationsSlot/index.jsx b/src/plugin-slots/CourseExitPluginSlots/CourseRecommendationsSlot/index.tsx similarity index 69% rename from src/plugin-slots/CourseExitPluginSlots/CourseRecommendationsSlot/index.jsx rename to src/plugin-slots/CourseExitPluginSlots/CourseRecommendationsSlot/index.tsx index 4e222a832a..9fbb1c38c0 100644 --- a/src/plugin-slots/CourseExitPluginSlots/CourseRecommendationsSlot/index.jsx +++ b/src/plugin-slots/CourseExitPluginSlots/CourseRecommendationsSlot/index.tsx @@ -2,7 +2,11 @@ import PropTypes from 'prop-types'; import { PluginSlot } from '@openedx/frontend-plugin-framework'; import CourseRecommendations from '../../../courseware/course/course-exit/CourseRecommendations'; -const CourseRecommendationsSlot = ({ variant }) => ( +interface Props { + variant: string +} + +export const CourseRecommendationsSlot: React.FC = ({ variant }) => ( ( ); -CourseRecommendationsSlot.propTypes = { - variant: PropTypes.string.isRequired, -}; - -export default CourseRecommendationsSlot; diff --git a/src/plugin-slots/CourseExitPluginSlots/DashboardFootnoteLinkPluginSlot/index.jsx b/src/plugin-slots/CourseExitPluginSlots/DashboardFootnoteLinkPluginSlot/index.tsx similarity index 76% rename from src/plugin-slots/CourseExitPluginSlots/DashboardFootnoteLinkPluginSlot/index.jsx rename to src/plugin-slots/CourseExitPluginSlots/DashboardFootnoteLinkPluginSlot/index.tsx index bab443151b..fcd16966bf 100644 --- a/src/plugin-slots/CourseExitPluginSlots/DashboardFootnoteLinkPluginSlot/index.jsx +++ b/src/plugin-slots/CourseExitPluginSlots/DashboardFootnoteLinkPluginSlot/index.tsx @@ -9,7 +9,12 @@ import messages from '../../../courseware/course/course-exit/messages'; import { logClick } from '../../../courseware/course/course-exit/utils'; import { useModel } from '../../../generic/model-store'; -const DashboardFootnoteLink = ({ variant, content }) => { +interface LinkProps { + variant: string, + content: { destination: string } +} + +const DashboardFootnoteLink: React.FC = ({ variant, content }) => { const intl = useIntl(); const { courseId } = useSelector(state => state.courseware); const { org } = useModel('courseHomeMeta', courseId); @@ -27,14 +32,11 @@ const DashboardFootnoteLink = ({ variant, content }) => { ); }; -DashboardFootnoteLink.propTypes = { - variant: PropTypes.string.isRequired, - content: PropTypes.shape({ - destination: PropTypes.string.isRequired, - }).isRequired, -}; +interface PluginProps { + variant: string +} -const DashboardFootnoteLinkPluginSlot = ({ variant }) => { +export const DashboardFootnoteLinkPluginSlot: React.FC = ({ variant }) => { const destination = `${getConfig().LMS_BASE_URL}/dashboard`; return ( @@ -42,9 +44,3 @@ const DashboardFootnoteLinkPluginSlot = ({ variant }) => { ); }; - -DashboardFootnoteLinkPluginSlot.propTypes = { - variant: PropTypes.string.isRequired, -}; - -export default DashboardFootnoteLinkPluginSlot; From 80faef7c95634db72c14bd06e6adf5c4420631bf Mon Sep 17 00:00:00 2001 From: Jansen Kantor Date: Thu, 24 Apr 2025 15:15:14 -0400 Subject: [PATCH 4/9] fixup! refactor: change plugin files to tsx,remove propTypes --- .../CourseExitViewCoursesPluginSlot/index.tsx | 5 +---- .../CourseRecommendationsSlot/index.tsx | 2 -- .../DashboardFootnoteLinkPluginSlot/index.tsx | 1 - src/plugin-slots/CourseExitPluginSlots/index.jsx | 6 +++--- 4 files changed, 4 insertions(+), 10 deletions(-) diff --git a/src/plugin-slots/CourseExitPluginSlots/CourseExitViewCoursesPluginSlot/index.tsx b/src/plugin-slots/CourseExitPluginSlots/CourseExitViewCoursesPluginSlot/index.tsx index a876722a0f..6761db4dc3 100644 --- a/src/plugin-slots/CourseExitPluginSlots/CourseExitViewCoursesPluginSlot/index.tsx +++ b/src/plugin-slots/CourseExitPluginSlots/CourseExitViewCoursesPluginSlot/index.tsx @@ -1,5 +1,4 @@ import { Button } from '@openedx/paragon'; -import PropTypes from 'prop-types'; import { getConfig } from '@edx/frontend-platform'; import { PluginSlot } from '@openedx/frontend-plugin-framework'; import { useIntl } from '@edx/frontend-platform/i18n'; @@ -23,7 +22,7 @@ const ViewCoursesLink: React.FC = ({ content }) => { ); }; -const CourseExitViewCoursesPluginSlot: React.FC = () => { +export const CourseExitViewCoursesPluginSlot: React.FC = () => { const href = `${getConfig().LMS_BASE_URL}/dashboard`; return ( @@ -31,5 +30,3 @@ const CourseExitViewCoursesPluginSlot: React.FC = () => { ); }; - -export default CourseExitViewCoursesPluginSlot; diff --git a/src/plugin-slots/CourseExitPluginSlots/CourseRecommendationsSlot/index.tsx b/src/plugin-slots/CourseExitPluginSlots/CourseRecommendationsSlot/index.tsx index 9fbb1c38c0..8e0b5a1f22 100644 --- a/src/plugin-slots/CourseExitPluginSlots/CourseRecommendationsSlot/index.tsx +++ b/src/plugin-slots/CourseExitPluginSlots/CourseRecommendationsSlot/index.tsx @@ -1,4 +1,3 @@ -import PropTypes from 'prop-types'; import { PluginSlot } from '@openedx/frontend-plugin-framework'; import CourseRecommendations from '../../../courseware/course/course-exit/CourseRecommendations'; @@ -14,4 +13,3 @@ export const CourseRecommendationsSlot: React.FC = ({ variant }) => ( ); - diff --git a/src/plugin-slots/CourseExitPluginSlots/DashboardFootnoteLinkPluginSlot/index.tsx b/src/plugin-slots/CourseExitPluginSlots/DashboardFootnoteLinkPluginSlot/index.tsx index fcd16966bf..353252420b 100644 --- a/src/plugin-slots/CourseExitPluginSlots/DashboardFootnoteLinkPluginSlot/index.tsx +++ b/src/plugin-slots/CourseExitPluginSlots/DashboardFootnoteLinkPluginSlot/index.tsx @@ -1,4 +1,3 @@ -import PropTypes from 'prop-types'; import { Hyperlink } from '@openedx/paragon'; import { getConfig } from '@edx/frontend-platform'; import { PluginSlot } from '@openedx/frontend-plugin-framework'; diff --git a/src/plugin-slots/CourseExitPluginSlots/index.jsx b/src/plugin-slots/CourseExitPluginSlots/index.jsx index 2e65103b0e..235ac99af5 100644 --- a/src/plugin-slots/CourseExitPluginSlots/index.jsx +++ b/src/plugin-slots/CourseExitPluginSlots/index.jsx @@ -1,6 +1,6 @@ -import DashboardFootnoteLinkPluginSlot from './DashboardFootnoteLinkPluginSlot'; -import CourseRecommendationsSlot from './CourseRecommendationsSlot'; -import CourseExitViewCoursesPluginSlot from './CourseExitViewCoursesPluginSlot'; +import { DashboardFootnoteLinkPluginSlot } from './DashboardFootnoteLinkPluginSlot'; +import { CourseRecommendationsSlot } from './CourseRecommendationsSlot'; +import { CourseExitViewCoursesPluginSlot } from './CourseExitViewCoursesPluginSlot'; export { DashboardFootnoteLinkPluginSlot, From bafa2b9f56cc10733de5375c2f6c1bb011523f7d Mon Sep 17 00:00:00 2001 From: Jansen Kantor Date: Thu, 24 Apr 2025 16:17:49 -0400 Subject: [PATCH 5/9] fixup! fixup! refactor: change plugin files to tsx,remove propTypes --- .../CourseExitViewCoursesPluginSlot/index.tsx | 2 +- .../CourseRecommendationsSlot/index.tsx | 6 +++--- .../DashboardFootnoteLinkPluginSlot/index.tsx | 14 ++++++++------ 3 files changed, 12 insertions(+), 10 deletions(-) diff --git a/src/plugin-slots/CourseExitPluginSlots/CourseExitViewCoursesPluginSlot/index.tsx b/src/plugin-slots/CourseExitPluginSlots/CourseExitViewCoursesPluginSlot/index.tsx index 6761db4dc3..2b7e0decdb 100644 --- a/src/plugin-slots/CourseExitPluginSlots/CourseExitViewCoursesPluginSlot/index.tsx +++ b/src/plugin-slots/CourseExitPluginSlots/CourseExitViewCoursesPluginSlot/index.tsx @@ -8,7 +8,7 @@ interface Props { content: { href: string } } -const ViewCoursesLink: React.FC = ({ content }) => { +const ViewCoursesLink: React.FC = ({ content }: Props) => { const intl = useIntl(); return (
diff --git a/src/plugin-slots/CourseExitPluginSlots/CourseRecommendationsSlot/index.tsx b/src/plugin-slots/CourseExitPluginSlots/CourseRecommendationsSlot/index.tsx index 8e0b5a1f22..efe5de3352 100644 --- a/src/plugin-slots/CourseExitPluginSlots/CourseRecommendationsSlot/index.tsx +++ b/src/plugin-slots/CourseExitPluginSlots/CourseRecommendationsSlot/index.tsx @@ -2,14 +2,14 @@ import { PluginSlot } from '@openedx/frontend-plugin-framework'; import CourseRecommendations from '../../../courseware/course/course-exit/CourseRecommendations'; interface Props { - variant: string + variant: string; } -export const CourseRecommendationsSlot: React.FC = ({ variant }) => ( +export const CourseRecommendationsSlot: React.FC = ({ variant }: Props) => ( -); +); \ No newline at end of file diff --git a/src/plugin-slots/CourseExitPluginSlots/DashboardFootnoteLinkPluginSlot/index.tsx b/src/plugin-slots/CourseExitPluginSlots/DashboardFootnoteLinkPluginSlot/index.tsx index 353252420b..6084955957 100644 --- a/src/plugin-slots/CourseExitPluginSlots/DashboardFootnoteLinkPluginSlot/index.tsx +++ b/src/plugin-slots/CourseExitPluginSlots/DashboardFootnoteLinkPluginSlot/index.tsx @@ -2,20 +2,22 @@ import { Hyperlink } from '@openedx/paragon'; import { getConfig } from '@edx/frontend-platform'; import { PluginSlot } from '@openedx/frontend-plugin-framework'; import { useIntl } from '@edx/frontend-platform/i18n'; -import { useSelector } from 'react-redux'; import { getAuthenticatedUser } from '@edx/frontend-platform/auth'; import messages from '../../../courseware/course/course-exit/messages'; import { logClick } from '../../../courseware/course/course-exit/utils'; import { useModel } from '../../../generic/model-store'; +import { useContextId } from '../../../data/hooks'; interface LinkProps { - variant: string, - content: { destination: string } + variant: string; + content: { + destination: string; + }; } -const DashboardFootnoteLink: React.FC = ({ variant, content }) => { +const DashboardFootnoteLink: React.FC = ({ variant, content }: LinkProps) => { const intl = useIntl(); - const { courseId } = useSelector(state => state.courseware); + const courseId = useContextId(); const { org } = useModel('courseHomeMeta', courseId); const { administrator } = getAuthenticatedUser(); const { destination } = content; @@ -35,7 +37,7 @@ interface PluginProps { variant: string } -export const DashboardFootnoteLinkPluginSlot: React.FC = ({ variant }) => { +export const DashboardFootnoteLinkPluginSlot: React.FC = ({ variant }: PluginProps) => { const destination = `${getConfig().LMS_BASE_URL}/dashboard`; return ( From 36ff071ce15261b261424181e814851de2fecb79 Mon Sep 17 00:00:00 2001 From: Jansen Kantor Date: Thu, 24 Apr 2025 16:19:12 -0400 Subject: [PATCH 6/9] fixup! fixup! fixup! refactor: change plugin files to tsx,remove propTypes --- .../CourseExitPluginSlots/CourseRecommendationsSlot/index.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/plugin-slots/CourseExitPluginSlots/CourseRecommendationsSlot/index.tsx b/src/plugin-slots/CourseExitPluginSlots/CourseRecommendationsSlot/index.tsx index efe5de3352..e869310b48 100644 --- a/src/plugin-slots/CourseExitPluginSlots/CourseRecommendationsSlot/index.tsx +++ b/src/plugin-slots/CourseExitPluginSlots/CourseRecommendationsSlot/index.tsx @@ -12,4 +12,4 @@ export const CourseRecommendationsSlot: React.FC = ({ variant }: Props) = > -); \ No newline at end of file +); From 13197bd43db52eaf587cb2ea519ed2b86fb1903c Mon Sep 17 00:00:00 2001 From: Jansen Kantor Date: Thu, 24 Apr 2025 16:31:07 -0400 Subject: [PATCH 7/9] fix: accidentally committed test code --- .../course/course-exit/CourseCelebration.jsx | 13 ++----------- 1 file changed, 2 insertions(+), 11 deletions(-) diff --git a/src/courseware/course/course-exit/CourseCelebration.jsx b/src/courseware/course/course-exit/CourseCelebration.jsx index 02ba94ac67..08100ffec1 100644 --- a/src/courseware/course/course-exit/CourseCelebration.jsx +++ b/src/courseware/course/course-exit/CourseCelebration.jsx @@ -53,20 +53,11 @@ const CourseCelebration = () => { const { org, - // verifiedMode, + verifiedMode, canViewCertificate, userTimezone, } = useModel('courseHomeMeta', courseId); - const verifiedMode = { - accessExpirationDate: null, - currency: 'USD', - currencySymbol: '$', - price: 99, - sku: '765F6C2', - upgradeUrl: 'https://commerce-coordinator.edx.org/lms/payment_page_redirect/?sku=765F6C2&course_run_key=course-v1%3AIBM%2BPY0101EN%2B2T2023', - }; - const { certStatus, certWebViewUrl, @@ -92,7 +83,7 @@ const CourseCelebration = () => { let certHeader; let visitEvent = 'celebration_generic'; // These cases are taken from the edx-platform `get_cert_data` function found in lms/courseware/views/views.py - switch ('audit_passing') { + switch (certStatus) { case 'downloadable': certHeader = intl.formatMessage(messages.certificateHeaderDownloadable); message = ( From 609abc114ee75ebe65c6a0bbcd19e9c71571a36d Mon Sep 17 00:00:00 2001 From: Jansen Kantor Date: Fri, 25 Apr 2025 14:31:13 -0400 Subject: [PATCH 8/9] fix: plugin-slot fixes --- .../CourseExitViewCoursesPluginSlot/index.tsx | 15 ++++++++++----- .../DashboardFootnoteLinkPluginSlot/index.tsx | 16 +++++++++------- 2 files changed, 19 insertions(+), 12 deletions(-) diff --git a/src/plugin-slots/CourseExitPluginSlots/CourseExitViewCoursesPluginSlot/index.tsx b/src/plugin-slots/CourseExitPluginSlots/CourseExitViewCoursesPluginSlot/index.tsx index 2b7e0decdb..1948f4447e 100644 --- a/src/plugin-slots/CourseExitPluginSlots/CourseExitViewCoursesPluginSlot/index.tsx +++ b/src/plugin-slots/CourseExitPluginSlots/CourseExitViewCoursesPluginSlot/index.tsx @@ -5,16 +5,16 @@ import { useIntl } from '@edx/frontend-platform/i18n'; import messages from '../../../courseware/course/course-exit/messages'; interface Props { - content: { href: string } + href: string } -const ViewCoursesLink: React.FC = ({ content }: Props) => { +const ViewCoursesLink: React.FC = ({ href }: Props) => { const intl = useIntl(); return (
@@ -25,8 +25,13 @@ const ViewCoursesLink: React.FC = ({ content }: Props) => { export const CourseExitViewCoursesPluginSlot: React.FC = () => { const href = `${getConfig().LMS_BASE_URL}/dashboard`; return ( - - + + ); }; diff --git a/src/plugin-slots/CourseExitPluginSlots/DashboardFootnoteLinkPluginSlot/index.tsx b/src/plugin-slots/CourseExitPluginSlots/DashboardFootnoteLinkPluginSlot/index.tsx index 6084955957..4bb9009531 100644 --- a/src/plugin-slots/CourseExitPluginSlots/DashboardFootnoteLinkPluginSlot/index.tsx +++ b/src/plugin-slots/CourseExitPluginSlots/DashboardFootnoteLinkPluginSlot/index.tsx @@ -10,17 +10,14 @@ import { useContextId } from '../../../data/hooks'; interface LinkProps { variant: string; - content: { - destination: string; - }; + destination: string; } -const DashboardFootnoteLink: React.FC = ({ variant, content }: LinkProps) => { +const DashboardFootnoteLink: React.FC = ({ variant, destination }: LinkProps) => { const intl = useIntl(); const courseId = useContextId(); const { org } = useModel('courseHomeMeta', courseId); const { administrator } = getAuthenticatedUser(); - const { destination } = content; return ( { const destination = `${getConfig().LMS_BASE_URL}/dashboard`; return ( - - + + ); }; From a936a870270adbd6209700b189b6b5cc62631f7f Mon Sep 17 00:00:00 2001 From: Jansen Kantor Date: Fri, 25 Apr 2025 14:32:23 -0400 Subject: [PATCH 9/9] chore: add ENTERPRISE_LEARNER_PORTAL_URL env var --- .env | 1 + .env.development | 1 + .env.test | 2 ++ src/index.jsx | 1 + 4 files changed, 5 insertions(+) diff --git a/.env b/.env index 917bdea634..3650d3304d 100644 --- a/.env +++ b/.env @@ -16,6 +16,7 @@ ECOMMERCE_BASE_URL='' ENABLE_JUMPNAV='true' ENABLE_NOTICES='' ENTERPRISE_LEARNER_PORTAL_HOSTNAME='' +ENTERPRISE_LEARNER_PORTAL_URL='' EXAMS_BASE_URL='' FAVICON_URL='' IGNORED_ERROR_REGEX='' diff --git a/.env.development b/.env.development index 51b6f4d7c9..2eff90c964 100644 --- a/.env.development +++ b/.env.development @@ -16,6 +16,7 @@ ECOMMERCE_BASE_URL='http://localhost:18130' ENABLE_JUMPNAV='true' ENABLE_NOTICES='' ENTERPRISE_LEARNER_PORTAL_HOSTNAME='localhost:8734' +ENTERPRISE_LEARNER_PORTAL_URL='http://localhost:8734' EXAMS_BASE_URL='' FAVICON_URL=https://edx-cdn.org/v3/default/favicon.ico IGNORED_ERROR_REGEX='' diff --git a/.env.test b/.env.test index f442f0aaea..b17621b0e3 100644 --- a/.env.test +++ b/.env.test @@ -16,6 +16,7 @@ ECOMMERCE_BASE_URL='http://localhost:18130' ENABLE_JUMPNAV='true' ENABLE_NOTICES='' ENTERPRISE_LEARNER_PORTAL_HOSTNAME='localhost:8734' +ENTERPRISE_LEARNER_PORTAL_URL='http://localhost:8734' EXAMS_BASE_URL='http://localhost:18740' FAVICON_URL=https://edx-cdn.org/v3/default/favicon.ico IGNORED_ERROR_REGEX='' @@ -48,3 +49,4 @@ TWITTER_URL='https://twitter.com/edXOnline' USER_INFO_COOKIE_NAME='edx-user-info' PRIVACY_POLICY_URL='http://localhost:18000/privacy' SHOW_UNGRADED_ASSIGNMENT_PROGRESS='' +ENTERPRISE_LEARNER_PORTAL_URL='http://localhost:Enterprise' diff --git a/src/index.jsx b/src/index.jsx index fafe7e6df3..72c4992ac7 100755 --- a/src/index.jsx +++ b/src/index.jsx @@ -170,6 +170,7 @@ initialize({ CREDIT_HELP_LINK_URL: process.env.CREDIT_HELP_LINK_URL || null, DISCUSSIONS_MFE_BASE_URL: process.env.DISCUSSIONS_MFE_BASE_URL || null, ENTERPRISE_LEARNER_PORTAL_HOSTNAME: process.env.ENTERPRISE_LEARNER_PORTAL_HOSTNAME || null, + ENTERPRISE_LEARNER_PORTAL_URL: process.env.ENTERPRISE_LEARNER_PORTAL_URL || null, ENABLE_JUMPNAV: process.env.ENABLE_JUMPNAV || null, ENABLE_NOTICES: process.env.ENABLE_NOTICES || null, INSIGHTS_BASE_URL: process.env.INSIGHTS_BASE_URL || null,