Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion src/data/api.ts
Original file line number Diff line number Diff line change
Expand Up @@ -247,7 +247,6 @@ export interface CourseSettingsData {
languageOptions: [string, string][];
lmsLinkForAboutPage: string;
licensingEnabled: boolean;
marketingEnabled: boolean;
mfeProctoredExamSettingsUrl: string;
platformName: string;
possiblePreRequisiteCourses: {
Expand Down
45 changes: 45 additions & 0 deletions src/plugin-slots/PageBannerSlot/Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -51,3 +51,48 @@ const config = {

export default config;
```

## Restoring the course enrollment card

Prior to the removal of `ENABLE_MKTG_SITE`, deployments running with `ENABLE_MKTG_SITE=False`
showed a "Course summary page" card in Schedule & Details instead of the promotional banner.
That card displayed a direct link to the LMS about/enrollment page and an "Invite your students"
mailto button.

If you want to restore that experience, you can use `CoursePromotionCard` — exported from
`basic-section` — via this slot. The slot passes `lmsLinkForAboutPage`, `courseDisplayName`,
and `platformName` as `pluginProps` so the card has everything it needs.

```jsx
import { DIRECT_PLUGIN, PLUGIN_OPERATIONS } from '@openedx/frontend-plugin-framework';
import { CoursePromotionCard } from '@edx/frontend-app-authoring/src/schedule-and-details/basic-section';

const config = {
pluginSlots: {
'org.openedx.frontend.authoring.page_banner.v1': {
plugins: [
{
op: PLUGIN_OPERATIONS.Hide,
widgetId: 'default_contents',
},
{
op: PLUGIN_OPERATIONS.Insert,
widget: {
id: 'course_promotion_card',
type: DIRECT_PLUGIN,
RenderWidget: ({ pluginProps }) => (
<CoursePromotionCard
lmsLinkForAboutPage={pluginProps.lmsLinkForAboutPage}
courseDisplayName={pluginProps.courseDisplayName}
platformName={pluginProps.platformName}
/>
),
},
},
],
},
},
};

export default config;
```
9 changes: 9 additions & 0 deletions src/plugin-slots/PageBannerSlot/index.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,28 @@ export interface PageBannerSlotProps {
show: boolean;
onDismiss: () => void;
children: ReactNode;
lmsLinkForAboutPage?: string;
courseDisplayName?: string;
platformName?: string;
}

const PageBannerSlot: React.FC<PageBannerSlotProps> = ({
show,
onDismiss,
children,
lmsLinkForAboutPage,
courseDisplayName,
platformName,
}) => (
<PluginSlot
id="org.openedx.frontend.authoring.page_banner.v1"
idAliases={['page_banner_slot']}
pluginProps={{
show,
onDismiss,
lmsLinkForAboutPage,
courseDisplayName,
platformName,
}}
>
<div className="align-items-start">
Expand Down
1 change: 0 additions & 1 deletion src/schedule-and-details/__mocks__/courseSettings.js
Original file line number Diff line number Diff line change
Expand Up @@ -25,7 +25,6 @@ module.exports = {
['uk', 'Ukrainian'],
],
lmsLinkForAboutPage: 'http://localhost:18000/courses/course-v1:edX+M12+2T2023/about',
marketingEnabled: true,
mfeProctoredExamSettingsUrl: '',
possiblePreRequisiteCourses: [
{
Expand Down
34 changes: 2 additions & 32 deletions src/schedule-and-details/basic-section/BasicSection.test.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import React from 'react';
import { render } from '@testing-library/react';
import { IntlProvider } from '@edx/frontend-platform/i18n';

import { INVITE_STUDENTS_LINK_ID } from './constants';
import messages from './messages';
import BasicSection from '.';

Expand All @@ -19,7 +18,6 @@ describe('<BasicSection />', () => {
courseNumber: 'bar number',
run: 'foo run',
lmsLinkForAboutPage: 'link://to',
marketingEnabled: true,
courseDisplayName: 'foo course',
platformName: 'Your platform name here',
};
Expand All @@ -40,41 +38,13 @@ describe('<BasicSection />', () => {
expect(getByText(props.run)).toBeInTheDocument();
});

it('shows the page banner if the marketingEnabled is true', () => {
const { getByText, queryAllByText } = render(<RootWrapper {...props} />);
it('shows the page banner', () => {
const { getByText } = render(<RootWrapper {...props} />);
expect(
getByText(`Promoting your course with ${props.platformName}`),
).toBeInTheDocument();
expect(
getByText(messages.basicBannerText.defaultMessage),
).toBeInTheDocument();
expect(queryAllByText('Course summary page').length).toBe(0);
});

it('shows the course promotion if the marketingEnabled is false', () => {
const initialProps = { ...props, marketingEnabled: false };
const { getByText, getByRole, queryAllByText } = render(
<RootWrapper {...initialProps} />,
);
const inviteButton = getByRole('button', {
name: messages.basicPromotionButton.defaultMessage,
});

expect(getByText(/Course Summary Page/i)).toBeInTheDocument();
expect(
getByText(/(for student enrollment and access)/i),
).toBeInTheDocument();
expect(getByText(props.lmsLinkForAboutPage)).toBeInTheDocument();
expect(inviteButton).toBeInTheDocument();
expect(queryAllByText(`Promoting your course with ${props.platformName}`).length).toBe(0);
});

it('checks link link to invite', () => {
const initialProps = { ...props, marketingEnabled: false };
const { getByTestId } = render(<RootWrapper {...initialProps} />);
const inviteLink = getByTestId(INVITE_STUDENTS_LINK_ID);
expect(decodeURIComponent(inviteLink.href)).toEqual(
`mailto:${process.env.INVITE_STUDENTS_EMAIL_TO}?body=The course ${props.courseDisplayName}, provided by ${props.platformName}, is open for enrollment. Please navigate to this course at ${props.lmsLinkForAboutPage} to enroll.&subject=Enroll in ${props.courseDisplayName}.`,
);
});
});
85 changes: 85 additions & 0 deletions src/schedule-and-details/basic-section/CoursePromotionCard.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
import React from 'react';
import PropTypes from 'prop-types';
import { useIntl, FormattedMessage } from '@edx/frontend-platform/i18n';
import {
Button,
Card,
MailtoLink,
Hyperlink,
} from '@openedx/paragon';
import { Email as EmailIcon } from '@openedx/paragon/icons';

import { INVITE_STUDENTS_LINK_ID } from './constants';
import messages from './messages';

const CoursePromotionCard = ({ lmsLinkForAboutPage, courseDisplayName, platformName }) => {
const intl = useIntl();

const emailSubject = intl.formatMessage(
{
id: 'course-authoring.schedule.basic.email.subject',
defaultMessage: 'Enroll in {courseDisplayName}.',
},
{ courseDisplayName },
);

const emailBody = intl.formatMessage(
{
id: 'course-authoring.schedule.basic.email.body',
defaultMessage:
'The course {courseDisplayName}, provided by {platformName}, is open for enrollment. Please navigate to this course at {lmsLinkForAboutPage} to enroll.',
},
{ courseDisplayName, platformName, lmsLinkForAboutPage },
);

const promotionTitle = (
<FormattedMessage
id="course-authoring.schedule.basic.promotion.title"
defaultMessage="Course summary page {smallText}"
values={{
smallText: <small>(for student enrollment and access)</small>,
}}
/>
);

return (
<Card>
<Card.Header
className="h4 px-3 text-gray-500"
title={promotionTitle}
size="sm"
/>
<Card.Section className="px-3 py-1">
<Hyperlink
destination={lmsLinkForAboutPage}
className="lead info-500 small text-decoration-none"
target="_blank"
showLaunchIcon={false}
>
{lmsLinkForAboutPage}
</Hyperlink>
</Card.Section>
<Card.Divider />
<Card.Footer className="p-3 justify-content-start">
<MailtoLink
to={process.env.INVITE_STUDENTS_EMAIL_TO}
subject={emailSubject}
body={emailBody}
data-testid={INVITE_STUDENTS_LINK_ID}
>
<Button variant="outline-primary" iconBefore={EmailIcon} size="sm">
{intl.formatMessage(messages.basicPromotionButton)}
</Button>
</MailtoLink>
</Card.Footer>
</Card>
);
};

CoursePromotionCard.propTypes = {
lmsLinkForAboutPage: PropTypes.string.isRequired,
courseDisplayName: PropTypes.string.isRequired,
platformName: PropTypes.string.isRequired,
};

export default CoursePromotionCard;
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
import React from 'react';
import { render } from '@testing-library/react';
import { IntlProvider } from '@edx/frontend-platform/i18n';

import { INVITE_STUDENTS_LINK_ID } from './constants';
import messages from './messages';
import CoursePromotionCard from './CoursePromotionCard';

describe('<CoursePromotionCard />', () => {
const RootWrapper = (props) => (
<IntlProvider locale="en">
<CoursePromotionCard {...props} />
</IntlProvider>
);

const props = {
lmsLinkForAboutPage: 'link://to',
courseDisplayName: 'foo course',
platformName: 'Your platform name here',
};

it('renders the course promotion card', () => {
const { getByText, getByRole } = render(<RootWrapper {...props} />);
const inviteButton = getByRole('button', {
name: messages.basicPromotionButton.defaultMessage,
});

expect(getByText(/Course Summary Page/i)).toBeInTheDocument();
expect(
getByText(/(for student enrollment and access)/i),
).toBeInTheDocument();
expect(getByText(props.lmsLinkForAboutPage)).toBeInTheDocument();
expect(inviteButton).toBeInTheDocument();
});

it('generates correct invite mailto link', () => {
const { getByTestId } = render(<RootWrapper {...props} />);
const inviteLink = getByTestId(INVITE_STUDENTS_LINK_ID);
expect(decodeURIComponent(inviteLink.href)).toEqual(
`mailto:${process.env.INVITE_STUDENTS_EMAIL_TO}?body=The course ${props.courseDisplayName}, provided by ${props.platformName}, is open for enrollment. Please navigate to this course at ${props.lmsLinkForAboutPage} to enroll.&subject=Enroll in ${props.courseDisplayName}.`,
);
});
});
Loading
Loading