feat: add progress certificate status plugin slot (#1551)

This commit is contained in:
Kristin Aoki
2024-12-11 07:24:33 -05:00
committed by GitHub
parent dafdcad2b4
commit 8a6fa937ea
5 changed files with 100 additions and 30 deletions

View File

@@ -1,10 +1,8 @@
import React, { useEffect } from 'react';
import { useEffect } from 'react';
import { useDispatch, useSelector } from 'react-redux';
import { sendTrackEvent } from '@edx/frontend-platform/analytics';
import { getAuthenticatedUser } from '@edx/frontend-platform/auth';
import {
FormattedDate, FormattedMessage, injectIntl, intlShape,
} from '@edx/frontend-platform/i18n';
import { FormattedDate, FormattedMessage, useIntl } from '@edx/frontend-platform/i18n';
import { Button, Card } from '@openedx/paragon';
import { getConfig } from '@edx/frontend-platform';
@@ -13,8 +11,10 @@ import { COURSE_EXIT_MODES, getCourseExitMode } from '../../../courseware/course
import { DashboardLink, IdVerificationSupportLink, ProfileLink } from '../../../shared/links';
import { requestCert } from '../../data/thunks';
import messages from './messages';
import ProgressCertificateStatusSlot from '../../../plugin-slots/ProgressCertificateStatusSlot';
const CertificateStatus = ({ intl }) => {
const CertificateStatus = () => {
const intl = useIntl();
const {
courseId,
} = useSelector(state => state.courseHome);
@@ -215,7 +215,6 @@ const CertificateStatus = ({ intl }) => {
});
// eslint-disable-next-line react-hooks/exhaustive-deps
}, []);
if (!certCase) {
return null;
}
@@ -243,32 +242,32 @@ const CertificateStatus = ({ intl }) => {
return (
<section data-testid="certificate-status-component" className="text-dark-700 mb-4">
<Card className="bg-light-200 raised-card">
<Card.Header title={header} />
<Card.Section className="small text-gray-700">
{body}
</Card.Section>
<Card.Footer>
{buttonText && (buttonLocation || buttonAction) && (
<Button
variant="outline-brand"
onClick={() => {
logCertificateStatusButtonClicked(certStatus);
if (buttonAction) { buttonAction(); }
}}
href={buttonLocation}
block
>
{buttonText}
</Button>
)}
</Card.Footer>
<ProgressCertificateStatusSlot courseId={courseId}>
<div id={`${certCase}_certificate_status`}>
<Card.Header title={header} />
<Card.Section className="small text-gray-700">
{body}
</Card.Section>
<Card.Footer>
{buttonText && (buttonLocation || buttonAction) && (
<Button
variant="outline-brand"
onClick={() => {
logCertificateStatusButtonClicked(certStatus);
if (buttonAction) { buttonAction(); }
}}
href={buttonLocation}
block
>
{buttonText}
</Button>
)}
</Card.Footer>
</div>
</ProgressCertificateStatusSlot>
</Card>
</section>
);
};
CertificateStatus.propTypes = {
intl: intlShape.isRequired,
};
export default injectIntl(CertificateStatus);
export default CertificateStatus;

View File

@@ -0,0 +1,53 @@
# Unit Title Slot
### Slot ID: `progress_certificate_status_slot`
### Props:
* `courseId`
## Description
This slot is used for modify the content in the CertificateStatus in the progress page for specific enrollment tracks.
## Example
The following `env.config.jsx` will render the `RenderWidget.props.id` of the course as `<p>` element.
### Default content
![Certificate Status slot with default content](./screenshot_default.png)
### Replaced with custom component
![Default content id showing in trigger slot](./screenshot_custom.png)
```js
import { DIRECT_PLUGIN, PLUGIN_OPERATIONS } from '@openedx/frontend-plugin-framework';
const modifyWidget = (widget) => {
const { RenderWidget } = widget;
if (RenderWidget.props.id.includes('upgrade')) {
widget.RenderWidget = (
<div className='m-3'>
<h3>Upgrade certificate</h3>
<p>{RenderWidget.props.id}</p>
</div>
)
}
return widget;
}
const config = {
pluginSlots: {
progress_certificate_status_slot: {
keepDefault: true,
plugins: [{
op: PLUGIN_OPERATIONS.Modify,
widgetId: 'default_contents',
// Insert custom content top modify certificate status
fn: modifyWidget,
}],
}
},
}
export default config;
```

View File

@@ -0,0 +1,18 @@
import PropTypes from 'prop-types';
import { PluginSlot } from '@openedx/frontend-plugin-framework';
const ProgressCertificateStatusSlot = ({ courseId, children }) => (
<PluginSlot
id="progress_certificate_status_slot"
pluginProps={{ courseId }}
>
{children}
</PluginSlot>
);
ProgressCertificateStatusSlot.propTypes = {
courseId: PropTypes.string.isRequired,
children: PropTypes.node.isRequired,
};
export default ProgressCertificateStatusSlot;

Binary file not shown.

After

Width:  |  Height:  |  Size: 26 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB