diff --git a/src/course-home/outline-tab/OutlineTab.jsx b/src/course-home/outline-tab/OutlineTab.jsx
index ca26155f82..a48fdf1822 100644
--- a/src/course-home/outline-tab/OutlineTab.jsx
+++ b/src/course-home/outline-tab/OutlineTab.jsx
@@ -17,7 +17,6 @@ import { fetchOutlineTab } from '../data';
import messages from './messages';
import Section from './Section';
import ShiftDatesAlert from '../suggested-schedule-messaging/ShiftDatesAlert';
-import UpgradeNotification from '../../generic/upgrade-notification/UpgradeNotification';
import UpgradeToShiftDatesAlert from '../suggested-schedule-messaging/UpgradeToShiftDatesAlert';
import useCertificateAvailableAlert from './alerts/certificate-status-alert';
import useCourseEndAlert from './alerts/course-end-alert';
@@ -39,11 +38,9 @@ const OutlineTab = ({ intl }) => {
isSelfPaced,
org,
title,
- userTimezone,
} = useModel('courseHomeMeta', courseId);
const {
- accessExpiration,
courseBlocks: {
courses,
sections,
@@ -52,20 +49,12 @@ const OutlineTab = ({ intl }) => {
selectedGoal,
weeklyLearningGoalEnabled,
} = {},
- datesBannerInfo,
datesWidget: {
courseDateBlocks,
},
enableProctoredExams,
- offer,
- timeOffsetMillis,
- verifiedMode,
} = useModel('outline', courseId);
- const {
- marketingUrl,
- } = useModel('coursewareMeta', courseId);
-
const [expandAll, setExpandAll] = useState(false);
const navigate = useNavigate();
@@ -198,21 +187,7 @@ const OutlineTab = ({ intl }) => {
-
-
+ />
diff --git a/src/course-home/outline-tab/OutlineTab.test.jsx b/src/course-home/outline-tab/OutlineTab.test.jsx
index 817612d31e..b658eb84f9 100644
--- a/src/course-home/outline-tab/OutlineTab.test.jsx
+++ b/src/course-home/outline-tab/OutlineTab.test.jsx
@@ -5,7 +5,7 @@ import React from 'react';
import { MemoryRouter } from 'react-router-dom';
import { Factory } from 'rosie';
import { getConfig } from '@edx/frontend-platform';
-import { sendTrackEvent, sendTrackingLogEvent } from '@edx/frontend-platform/analytics';
+import { sendTrackEvent } from '@edx/frontend-platform/analytics';
import { getAuthenticatedHttpClient } from '@edx/frontend-platform/auth';
import MockAdapter from 'axios-mock-adapter';
import Cookies from 'js-cookie';
@@ -1176,80 +1176,6 @@ describe('Outline Tab', () => {
});
});
- describe('Upgrade Card', () => {
- it('renders title when upgrade is available', async () => {
- await fetchAndRender();
- expect(screen.queryByRole('heading', { name: 'Pursue a verified certificate' })).toBeInTheDocument();
- });
-
- it('displays link to upgrade', async () => {
- await fetchAndRender();
- expect(screen.getByRole('link', { name: 'Upgrade for $149' })).toBeInTheDocument();
- });
-
- it('viewing upgrade card sends analytics', async () => {
- sendTrackEvent.mockClear();
- sendTrackingLogEvent.mockClear();
- await fetchAndRender();
-
- expect(sendTrackEvent).toHaveBeenCalledTimes(1);
- expect(sendTrackEvent).toHaveBeenCalledWith('Promotion Viewed', {
- org_key: 'edX',
- courserun_key: courseId,
- creative: 'sidebarupsell',
- name: 'In-Course Verification Prompt',
- position: 'sidebar-message',
- promotion_id: 'courseware_verified_certificate_upsell',
- });
-
- expect(sendTrackingLogEvent).toHaveBeenCalledTimes(1);
- expect(sendTrackingLogEvent).toHaveBeenCalledWith('edx.bi.course.upgrade.sidebarupsell.displayed', {
- org_key: 'edX',
- courserun_key: courseId,
- });
- });
-
- it('clicking upgrade link sends analytics', async () => {
- await fetchAndRender();
-
- // Clearing after render to remove any events sent on view (ex. 'Promotion Viewed')
- sendTrackEvent.mockClear();
- sendTrackingLogEvent.mockClear();
- const upgradeButton = screen.getByRole('link', { name: 'Upgrade for $149' });
-
- fireEvent.click(upgradeButton);
-
- expect(sendTrackEvent).toHaveBeenCalledTimes(2);
- expect(sendTrackEvent).toHaveBeenNthCalledWith(1, 'Promotion Clicked', {
- org_key: 'edX',
- courserun_key: courseId,
- creative: 'sidebarupsell',
- name: 'In-Course Verification Prompt',
- position: 'sidebar-message',
- promotion_id: 'courseware_verified_certificate_upsell',
- });
- expect(sendTrackEvent).toHaveBeenNthCalledWith(2, 'edx.bi.ecommerce.upsell_links_clicked', {
- org_key: 'edX',
- courserun_key: courseId,
- linkCategory: 'green_upgrade',
- linkName: 'course_home_green',
- linkType: 'button',
- pageName: 'course_home',
- });
-
- expect(sendTrackingLogEvent).toHaveBeenCalledTimes(2);
- expect(sendTrackingLogEvent).toHaveBeenNthCalledWith(1, 'edx.bi.course.upgrade.sidebarupsell.clicked', {
- org_key: 'edX',
- courserun_key: courseId,
- });
- expect(sendTrackingLogEvent).toHaveBeenNthCalledWith(2, 'edx.course.enrollment.upgrade.clicked', {
- org_key: 'edX',
- courserun_key: courseId,
- location: 'sidebar-message',
- });
- });
- });
-
describe('Account Activation Alert', () => {
beforeEach(() => {
const intersectionObserverMock = () => ({
diff --git a/src/courseware/course/new-sidebar/sidebars/discussions-notifications/notifications/NotificationsWidget.jsx b/src/courseware/course/new-sidebar/sidebars/discussions-notifications/notifications/NotificationsWidget.jsx
index 7e7087ac5b..47d4f707ab 100644
--- a/src/courseware/course/new-sidebar/sidebars/discussions-notifications/notifications/NotificationsWidget.jsx
+++ b/src/courseware/course/new-sidebar/sidebars/discussions-notifications/notifications/NotificationsWidget.jsx
@@ -3,7 +3,6 @@ import React, { useContext, useEffect, useMemo } from 'react';
import { sendTrackEvent } from '@edx/frontend-platform/analytics';
import { PluginSlot } from '@openedx/frontend-plugin-framework';
import { useModel } from '../../../../../../generic/model-store';
-import UpgradeNotification from '../../../../../../generic/upgrade-notification/UpgradeNotification';
import { WIDGETS } from '../../../../../../constants';
import SidebarContext from '../../../SidebarContext';
@@ -21,17 +20,11 @@ const NotificationsWidget = () => {
const course = useModel('coursewareMeta', courseId);
const {
- accessExpiration,
- contentTypeGatingEnabled,
end,
enrollmentEnd,
enrollmentMode,
enrollmentStart,
- marketingUrl,
- offer,
start,
- timeOffsetMillis,
- userTimezone,
verificationStatus,
} = course;
@@ -81,24 +74,7 @@ const NotificationsWidget = () => {
setNotificationCurrentState: setUpgradeNotificationCurrentState,
toggleSidebar: onToggleSidebar,
}}
- >
-
-
+ />
);
};
diff --git a/src/courseware/course/new-sidebar/sidebars/discussions-notifications/notifications/NotificationsWidget.test.jsx b/src/courseware/course/new-sidebar/sidebars/discussions-notifications/notifications/NotificationsWidget.test.jsx
index 11f9daf740..7e1cb16161 100644
--- a/src/courseware/course/new-sidebar/sidebars/discussions-notifications/notifications/NotificationsWidget.test.jsx
+++ b/src/courseware/course/new-sidebar/sidebars/discussions-notifications/notifications/NotificationsWidget.test.jsx
@@ -18,9 +18,22 @@ import SidebarContext from '../../../SidebarContext';
import NotificationsWidget from './NotificationsWidget';
import setupDiscussionSidebar from '../../../../test-utils';
-initializeMockApp();
jest.mock('@edx/frontend-platform/analytics');
+/* eslint-disable react/prop-types */
+jest.mock('@openedx/frontend-plugin-framework', () => ({
+ ...jest.requireActual('@openedx/frontend-plugin-framework'),
+ Plugin: () => 'Plugin',
+ PluginSlot: ({ id, pluginProps }) => (
+
+
+ PluginSlot_{id}
+
+ ),
+}));
+
+initializeMockApp();
+
describe('NotificationsWidget', () => {
let axiosMock;
let store;
@@ -93,27 +106,6 @@ describe('NotificationsWidget', () => {
expect(screen.getByTestId('notification_widget_slot')).toBeInTheDocument();
});
- it('renders upgrade card', async () => {
- await fetchAndRender(
-
-
- ,
- );
-
- // The Upgrade Notification should be inside the PluginSlot.
- const UpgradeNotification = document.querySelector('.upgrade-notification');
- expect(UpgradeNotification).toBeInTheDocument();
-
- expect(screen.getByRole('link', { name: 'Upgrade for $149' })).toBeInTheDocument();
- expect(screen.queryByText('You have no new notifications at this time.')).not.toBeInTheDocument();
- });
-
it('renders no notifications bar if no verified mode', async () => {
setMetadata({ verified_mode: null });
await fetchAndRender(
diff --git a/src/courseware/course/sequence/Unit/UnitSuspense.jsx b/src/courseware/course/sequence/Unit/UnitSuspense.jsx
index 09843a7164..299a491b6a 100644
--- a/src/courseware/course/sequence/Unit/UnitSuspense.jsx
+++ b/src/courseware/course/sequence/Unit/UnitSuspense.jsx
@@ -9,7 +9,6 @@ import PageLoading from '@src/generic/PageLoading';
import messages from '../messages';
import HonorCode from '../honor-code';
-import LockPaywall from '../lock-paywall';
import * as hooks from './hooks';
import { modelKeys } from './constants';
@@ -34,9 +33,7 @@ const UnitSuspense = ({
pluginProps={{
courseId,
}}
- >
-
-
+ />
)}
{shouldDisplayHonorCode && (
diff --git a/src/courseware/course/sequence/Unit/UnitSuspense.test.jsx b/src/courseware/course/sequence/Unit/UnitSuspense.test.jsx
index f47ee6b241..aa5c7e499d 100644
--- a/src/courseware/course/sequence/Unit/UnitSuspense.test.jsx
+++ b/src/courseware/course/sequence/Unit/UnitSuspense.test.jsx
@@ -7,7 +7,6 @@ import PageLoading from '@src/generic/PageLoading';
import messages from '../messages';
import HonorCode from '../honor-code';
-import LockPaywall from '../lock-paywall';
import hooks from './hooks';
import { modelKeys } from './constants';
@@ -24,7 +23,6 @@ jest.mock('react', () => ({
}));
jest.mock('../honor-code', () => 'HonorCode');
-jest.mock('../lock-paywall', () => 'LockPaywall');
jest.mock('@src/generic/model-store', () => ({ useModel: jest.fn() }));
jest.mock('@src/generic/PageLoading', () => 'PageLoading');
@@ -62,31 +60,6 @@ describe('UnitSuspense component', () => {
});
});
describe('output', () => {
- describe('LockPaywall', () => {
- const testNoPaywall = () => {
- it('does not display LockPaywall', () => {
- el = shallow();
- expect(el.instance.findByType(LockPaywall).length).toEqual(0);
- });
- };
- describe('gating not enabled', () => { testNoPaywall(); });
- describe('gating enabled, but no gated content included', () => {
- beforeEach(() => { mockModels(true, false); });
- testNoPaywall();
- });
- describe('gating enabled, gated content included', () => {
- beforeEach(() => { mockModels(true, true); });
- it('displays LockPaywall in Suspense wrapper with PageLoading fallback', () => {
- el = shallow();
- const [component] = el.instance.findByType(LockPaywall);
- expect(component.parent.type).toEqual('PluginSlot');
- expect(component.parent.parent.type).toEqual('Suspense');
- expect(component.parent.parent.props.fallback)
- .toEqual();
- expect(component.props.courseId).toEqual(props.courseId);
- });
- });
- });
describe('HonorCode', () => {
it('does not display HonorCode if useShouldDisplayHonorCode => false', () => {
hooks.useShouldDisplayHonorCode.mockReturnValueOnce(false);
diff --git a/src/courseware/course/sequence/Unit/index.test.jsx b/src/courseware/course/sequence/Unit/index.test.jsx
index 7ae0735ba4..3f4ac6fec0 100644
--- a/src/courseware/course/sequence/Unit/index.test.jsx
+++ b/src/courseware/course/sequence/Unit/index.test.jsx
@@ -28,7 +28,6 @@ jest.mock('../../bookmark/BookmarkButton', () => 'BookmarkButton');
jest.mock('./ContentIFrame', () => 'ContentIFrame');
jest.mock('./UnitSuspense', () => 'UnitSuspense');
jest.mock('../honor-code', () => 'HonorCode');
-jest.mock('../lock-paywall', () => 'LockPaywall');
jest.mock('@src/generic/model-store', () => ({
useModel: jest.fn(),
diff --git a/src/courseware/course/sequence/lock-paywall/LockPaywall.jsx b/src/courseware/course/sequence/lock-paywall/LockPaywall.jsx
deleted file mode 100644
index c1625c84c2..0000000000
--- a/src/courseware/course/sequence/lock-paywall/LockPaywall.jsx
+++ /dev/null
@@ -1,149 +0,0 @@
-import React, { useContext } from 'react';
-import PropTypes from 'prop-types';
-import classNames from 'classnames';
-import { sendTrackEvent } from '@edx/frontend-platform/analytics';
-import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
-import {
- Alert, Hyperlink, breakpoints, useWindowSize,
-} from '@openedx/paragon';
-import { Locked } from '@openedx/paragon/icons';
-import SidebarContext from '../../sidebar/SidebarContext';
-import messages from './messages';
-import certificateLocked from '../../../../generic/assets/edX_locked_certificate.png';
-import { useModel } from '../../../../generic/model-store';
-import { UpgradeButton } from '../../../../generic/upgrade-button';
-import {
- VerifiedCertBullet,
- UnlockGradedBullet,
- FullAccessBullet,
- SupportMissionBullet,
-} from '../../../../generic/upsell-bullets/UpsellBullets';
-
-const LockPaywall = ({
- intl,
- courseId,
-}) => {
- const { notificationTrayVisible } = useContext(SidebarContext);
- const course = useModel('coursewareMeta', courseId);
- const {
- accessExpiration,
- marketingUrl,
- offer,
- } = course;
-
- const {
- org, verifiedMode,
- } = useModel('courseHomeMeta', courseId);
-
- // the following variables are set and used for resposive layout to work with
- // whether the NotificationTray is open or not and if there's an offer with longer text
- const shouldDisplayBulletPointsBelowCertificate = useWindowSize().width <= breakpoints.large.minWidth;
- const shouldDisplayGatedContentOneColumn = useWindowSize().width <= breakpoints.extraLarge.minWidth
- && notificationTrayVisible;
- const shouldDisplayGatedContentTwoColumns = useWindowSize().width < breakpoints.large.minWidth
- && notificationTrayVisible;
- const shouldDisplayGatedContentTwoColumnsHalf = useWindowSize().width <= breakpoints.large.minWidth
- && !notificationTrayVisible;
- const shouldWrapTextOnButton = useWindowSize().width > breakpoints.extraSmall.minWidth;
-
- const accessExpirationDate = accessExpiration ? new Date(accessExpiration.expirationDate) : null;
- const pastExpirationDeadline = accessExpiration ? new Date(Date.now()) > accessExpirationDate : false;
-
- if (!verifiedMode) {
- return null;
- }
-
- const eventProperties = {
- org_key: org,
- courserun_key: courseId,
- };
-
- const logClick = () => {
- sendTrackEvent('edx.bi.ecommerce.upsell_links_clicked', {
- ...eventProperties,
- linkCategory: '(none)',
- linkName: 'in_course_upgrade',
- linkType: 'link',
- pageName: 'in_course',
- });
- };
-
- const logClickPastExpiration = () => {
- sendTrackEvent('edx.bi.ecommerce.gated_content.past_expiration.link_clicked', {
- ...eventProperties,
- linkCategory: 'gated_content',
- linkName: 'course_details',
- linkType: 'link',
- pageName: 'in_course',
- });
- };
-
- return (
-
-
-
-
- {intl.formatMessage(messages['learn.lockPaywall.title'])}
-
- {pastExpirationDeadline ? (
-
- {intl.formatMessage(messages['learn.lockPaywall.content.pastExpiration'])}
- {intl.formatMessage(messages['learn.lockPaywall.courseDetails'])}
-
- ) : (
-
- {intl.formatMessage(messages['learn.lockPaywall.content'])}
-
- )}
-
-
-
-
-
-
-
-
- {intl.formatMessage(messages['learn.lockPaywall.list.intro'])}
-
-
-
-
-
-
- {pastExpirationDeadline
- ? null
- : (
-
-
-
- )}
-
-
- );
-};
-LockPaywall.propTypes = {
- intl: intlShape.isRequired,
- courseId: PropTypes.string.isRequired,
-};
-export default injectIntl(LockPaywall);
diff --git a/src/courseware/course/sequence/lock-paywall/LockPaywall.scss b/src/courseware/course/sequence/lock-paywall/LockPaywall.scss
deleted file mode 100644
index 7bbee59b2c..0000000000
--- a/src/courseware/course/sequence/lock-paywall/LockPaywall.scss
+++ /dev/null
@@ -1,14 +0,0 @@
-.alert-content.lock-paywall-container {
- display: inline-flex;
- width: 100%;
-}
-
-.lock-paywall-container svg {
- color: $primary-700;
-}
-
-@media only screen and (min-width: 992px) and (max-width: 1100px) {
- .list-div {
- width: 62%;
- }
-}
diff --git a/src/courseware/course/sequence/lock-paywall/LockPaywall.test.jsx b/src/courseware/course/sequence/lock-paywall/LockPaywall.test.jsx
deleted file mode 100644
index 60ac428642..0000000000
--- a/src/courseware/course/sequence/lock-paywall/LockPaywall.test.jsx
+++ /dev/null
@@ -1,121 +0,0 @@
-import React from 'react';
-import { Factory } from 'rosie';
-import { sendTrackEvent } from '@edx/frontend-platform/analytics';
-
-import {
- fireEvent, initializeTestStore, render, screen,
-} from '../../../../setupTest';
-import LockPaywall from './LockPaywall';
-
-jest.mock('@edx/frontend-platform/analytics');
-
-describe('Lock Paywall', () => {
- let store;
- const mockData = { notificationTrayVisible: false };
-
- beforeAll(async () => {
- store = await initializeTestStore();
- const { courseware } = store.getState();
- Object.assign(mockData, {
- courseId: courseware.courseId,
- });
- });
-
- it('displays unlock link with price', () => {
- const {
- currencySymbol,
- price,
- upgradeUrl,
- } = store.getState().models.courseHomeMeta[mockData.courseId].verifiedMode;
- render();
-
- const upgradeLink = screen.getByRole('link', { name: `Upgrade for ${currencySymbol}${price}` });
- expect(upgradeLink).toHaveAttribute('href', `${upgradeUrl}`);
- });
-
- it('displays discounted price if there is an offer/first time purchase', async () => {
- const courseMetadata = Factory.build('courseMetadata', {
- offer: {
- code: 'EDXWELCOME',
- expiration_date: '2070-01-01T12:00:00Z',
- original_price: '$100',
- discounted_price: '$85',
- percentage: 15,
- upgrade_url: 'https://example.com/upgrade',
- },
- });
- const testStore = await initializeTestStore({ courseMetadata }, false);
- render(, { store: testStore });
-
- expect(screen.getByText(/Upgrade for/).textContent).toMatch('$85 ($100)');
- });
-
- it('sends analytics event onClick of unlock link', () => {
- sendTrackEvent.mockClear();
-
- const {
- currencySymbol,
- price,
- } = store.getState().models.courseHomeMeta[mockData.courseId].verifiedMode;
- render();
-
- const upgradeLink = screen.getByRole('link', { name: `Upgrade for ${currencySymbol}${price}` });
- fireEvent.click(upgradeLink);
-
- expect(sendTrackEvent).toHaveBeenCalledTimes(1);
- expect(sendTrackEvent).toHaveBeenCalledWith('edx.bi.ecommerce.upsell_links_clicked', {
- org_key: 'edX',
- courserun_key: mockData.courseId,
- linkCategory: '(none)',
- linkName: 'in_course_upgrade',
- linkType: 'link',
- pageName: 'in_course',
- });
- });
-
- it('does not display anything if course does not have verified mode', async () => {
- const courseHomeMetadata = Factory.build('courseHomeMetadata', { verified_mode: null });
- const testStore = await initializeTestStore({ courseHomeMetadata, excludeFetchSequence: true }, false);
- render(, { store: testStore });
-
- expect(screen.queryByTestId('lock-paywall-test-id')).not.toBeInTheDocument();
- });
-
- it('displays past expiration message if expiration date has expired', async () => {
- const courseMetadata = Factory.build('courseMetadata', {
- access_expiration: {
- expiration_date: '1995-02-22T05:00:00Z',
- },
- marketing_url: 'https://example.com/course-details',
- });
- const testStore = await initializeTestStore({ courseMetadata }, false);
- render(, { store: testStore });
- expect(screen.getByText('The upgrade deadline for this course passed. To upgrade, enroll in the next available session.')).toBeInTheDocument();
- expect(screen.getByText('View Course Details'))
- .toHaveAttribute('href', 'https://example.com/course-details');
- });
-
- it('sends analytics event onClick of past expiration course details link', async () => {
- sendTrackEvent.mockClear();
- const courseMetadata = Factory.build('courseMetadata', {
- access_expiration: {
- expiration_date: '1995-02-22T05:00:00Z',
- },
- marketing_url: 'https://example.com/course-details',
- });
- const testStore = await initializeTestStore({ courseMetadata }, false);
- render(, { store: testStore });
- const courseDetailsLink = await screen.getByText('View Course Details');
- fireEvent.click(courseDetailsLink);
-
- expect(sendTrackEvent).toHaveBeenCalledTimes(1);
- expect(sendTrackEvent).toHaveBeenCalledWith('edx.bi.ecommerce.gated_content.past_expiration.link_clicked', {
- org_key: 'edX',
- courserun_key: mockData.courseId,
- linkCategory: 'gated_content',
- linkName: 'course_details',
- linkType: 'link',
- pageName: 'in_course',
- });
- });
-});
diff --git a/src/courseware/course/sequence/lock-paywall/index.js b/src/courseware/course/sequence/lock-paywall/index.js
deleted file mode 100644
index d609d2794f..0000000000
--- a/src/courseware/course/sequence/lock-paywall/index.js
+++ /dev/null
@@ -1 +0,0 @@
-export { default } from './LockPaywall';
diff --git a/src/courseware/course/sequence/lock-paywall/messages.js b/src/courseware/course/sequence/lock-paywall/messages.js
deleted file mode 100644
index 54f51990b2..0000000000
--- a/src/courseware/course/sequence/lock-paywall/messages.js
+++ /dev/null
@@ -1,36 +0,0 @@
-import { defineMessages } from '@edx/frontend-platform/i18n';
-
-const messages = defineMessages({
- 'learn.lockPaywall.title': {
- id: 'learn.lockPaywall.title',
- defaultMessage: 'Graded assignments are locked',
- description: 'Heading for message shown to indicate that a piece of content is unavailable to audit track users.',
- },
- 'learn.lockPaywall.content': {
- id: 'learn.lockPaywall.content',
- defaultMessage: 'Upgrade to gain access to locked features like this one and get the most out of your course.',
- description: 'Message shown to indicate that a piece of content is unavailable to audit track users.',
- },
- 'learn.lockPaywall.content.pastExpiration': {
- id: 'learn.lockPaywall.content.pastExpiration',
- defaultMessage: 'The upgrade deadline for this course passed. To upgrade, enroll in the next available session. ',
- description: 'Message shown to indicate that a piece of content is unavailable to audit track users in a course where the expiration deadline has passed.',
- },
- 'learn.lockPaywall.courseDetails': {
- id: 'learn.lockPaywall.courseDetails',
- defaultMessage: 'View Course Details',
- description: 'Link to the course details page for this course with a past expiration date.',
- },
- 'learn.lockPaywall.example.alt': {
- id: 'learn.lockPaywall.example.alt',
- defaultMessage: 'Example Certificate',
- description: 'Alternate text displayed when the example certificate image cannot be displayed.',
- },
- 'learn.lockPaywall.list.intro': {
- id: 'learn.lockPaywall.list.intro',
- defaultMessage: 'When you upgrade, you:',
- description: 'Text displayed to introduce the list of benefits from upgrading.',
- },
-});
-
-export default messages;
diff --git a/src/courseware/course/sidebar/sidebars/notifications/NotificationTray.jsx b/src/courseware/course/sidebar/sidebars/notifications/NotificationTray.jsx
index de8ec204cb..f03cc36066 100644
--- a/src/courseware/course/sidebar/sidebars/notifications/NotificationTray.jsx
+++ b/src/courseware/course/sidebar/sidebars/notifications/NotificationTray.jsx
@@ -5,7 +5,6 @@ import { sendTrackEvent } from '@edx/frontend-platform/analytics';
import { PluginSlot } from '@openedx/frontend-plugin-framework';
import { getAuthenticatedUser } from '@edx/frontend-platform/auth';
import { useModel } from '@src/generic/model-store';
-import UpgradeNotification from '../../../../../generic/upgrade-notification/UpgradeNotification';
import messages from '../../../messages';
import SidebarBase from '../../common/SidebarBase';
@@ -23,17 +22,11 @@ const NotificationTray = ({ intl }) => {
const course = useModel('coursewareMeta', courseId);
const {
- accessExpiration,
- contentTypeGatingEnabled,
end,
enrollmentEnd,
enrollmentMode,
enrollmentStart,
- marketingUrl,
- offer,
start,
- timeOffsetMillis,
- userTimezone,
verificationStatus,
} = course;
@@ -88,23 +81,7 @@ const NotificationTray = ({ intl }) => {
notificationCurrentState: upgradeNotificationCurrentState,
setNotificationCurrentState: setUpgradeNotificationCurrentState,
}}
- >
-
-
+ />
) : (
{intl.formatMessage(messages.noNotificationsMessage)}
)}
diff --git a/src/courseware/course/sidebar/sidebars/notifications/NotificationTray.test.jsx b/src/courseware/course/sidebar/sidebars/notifications/NotificationTray.test.jsx
index 5a744add1a..a8831741f2 100644
--- a/src/courseware/course/sidebar/sidebars/notifications/NotificationTray.test.jsx
+++ b/src/courseware/course/sidebar/sidebars/notifications/NotificationTray.test.jsx
@@ -94,26 +94,6 @@ describe('NotificationTray', () => {
expect(screen.getByTestId('notification_tray_slot')).toBeInTheDocument();
});
- it('renders upgrade card', async () => {
- await fetchAndRender(
-
-
- ,
- );
-
- expect(document.querySelector('.upgrade-notification')).toBeInTheDocument();
-
- expect(screen.getByRole('link', { name: 'Upgrade for $149' }))
- .toBeInTheDocument();
- expect(screen.queryByText('You have no new notifications at this time.'))
- .not
- .toBeInTheDocument();
- });
-
it('renders no notifications message if no verified mode', async () => {
setMetadata({ verified_mode: null });
await fetchAndRender(
diff --git a/src/generic/upgrade-notification/UpgradeNotification.jsx b/src/generic/upgrade-notification/UpgradeNotification.jsx
deleted file mode 100644
index e9d3b5dde9..0000000000
--- a/src/generic/upgrade-notification/UpgradeNotification.jsx
+++ /dev/null
@@ -1,564 +0,0 @@
-import React, { useEffect } from 'react';
-import PropTypes from 'prop-types';
-import classNames from 'classnames';
-import {
- useIntl, FormattedDate, FormattedMessage, injectIntl,
-} from '@edx/frontend-platform/i18n';
-import { sendTrackEvent, sendTrackingLogEvent } from '@edx/frontend-platform/analytics';
-import { Button, Icon, IconButton } from '@openedx/paragon';
-import { Close } from '@openedx/paragon/icons';
-import { setLocalStorage } from '../../data/localStorage';
-import { UpgradeButton } from '../upgrade-button';
-import {
- VerifiedCertBullet,
- UnlockGradedBullet,
- FullAccessBullet,
- SupportMissionBullet,
-} from '../upsell-bullets/UpsellBullets';
-import messages from '../messages';
-
-const UpsellNoFBECardContent = () => (
-
-);
-
-const UpsellFBEFarAwayCardContent = () => (
-
-);
-
-const UpsellFBESoonCardContent = ({ accessExpirationDate, timezoneFormatArgs }) => {
- const includingAnyProgress = (
-
-
-
- );
-
- const date = (
-
- );
-
- const benefitsOfUpgrading = (
-
-
-
- );
-
- return (
-
- );
-};
-
-UpsellFBESoonCardContent.propTypes = {
- accessExpirationDate: PropTypes.PropTypes.instanceOf(Date).isRequired,
- timezoneFormatArgs: PropTypes.shape({
- timeZone: PropTypes.string,
- }),
-};
-
-UpsellFBESoonCardContent.defaultProps = {
- timezoneFormatArgs: {},
-};
-
-const PastExpirationCardContent = () => (
-
-);
-
-const ExpirationCountdown = ({
- courseId, hoursToExpiration, setupgradeNotificationCurrentState, type,
-}) => {
- let expirationText;
- if (hoursToExpiration >= 24) { // More than 1 day left
- // setupgradeNotificationCurrentState is available in NotificationTray (not course home)
- if (setupgradeNotificationCurrentState) {
- if (type === 'access') {
- setupgradeNotificationCurrentState('accessDaysLeft');
- setLocalStorage(`upgradeNotificationCurrentState.${courseId}`, 'accessDaysLeft');
- }
- if (type === 'offer') {
- setupgradeNotificationCurrentState('FPDdaysLeft');
- setLocalStorage(`upgradeNotificationCurrentState.${courseId}`, 'FPDdaysLeft');
- }
- }
- expirationText = (
-
- );
- } else if (hoursToExpiration >= 1) { // More than 1 hour left
- // setupgradeNotificationCurrentState is available in NotificationTray (not course home)
- if (setupgradeNotificationCurrentState) {
- if (type === 'access') {
- setupgradeNotificationCurrentState('accessHoursLeft');
- setLocalStorage(`upgradeNotificationCurrentState.${courseId}`, 'accessHoursLeft');
- }
- if (type === 'offer') {
- setupgradeNotificationCurrentState('FPDHoursLeft');
- setLocalStorage(`upgradeNotificationCurrentState.${courseId}`, 'FPDHoursLeft');
- }
- }
- expirationText = (
-
- );
- } else { // Less than 1 hour
- // setupgradeNotificationCurrentState is available in NotificationTray (not course home)
- if (setupgradeNotificationCurrentState) {
- if (type === 'access') {
- setupgradeNotificationCurrentState('accessLastHour');
- setLocalStorage(`upgradeNotificationCurrentState.${courseId}`, 'accessLastHour');
- }
- if (type === 'offer') {
- setupgradeNotificationCurrentState('FPDLastHour');
- setLocalStorage(`upgradeNotificationCurrentState.${courseId}`, 'FPDLastHour');
- }
- }
- expirationText = (
-
- );
- }
- return ({expirationText}
);
-};
-
-ExpirationCountdown.propTypes = {
- courseId: PropTypes.string.isRequired,
- hoursToExpiration: PropTypes.number.isRequired,
- setupgradeNotificationCurrentState: PropTypes.func,
- type: PropTypes.string,
-};
-ExpirationCountdown.defaultProps = {
- setupgradeNotificationCurrentState: null,
- type: null,
-};
-
-const AccessExpirationDateBanner = ({
- courseId, accessExpirationDate, timezoneFormatArgs, setupgradeNotificationCurrentState,
-}) => {
- if (setupgradeNotificationCurrentState) {
- setupgradeNotificationCurrentState('accessDateView');
- setLocalStorage(`upgradeNotificationCurrentState.${courseId}`, 'accessDateView');
- }
- return (
-
-
- ),
- }}
- />
-
- );
-};
-
-AccessExpirationDateBanner.propTypes = {
- courseId: PropTypes.string.isRequired,
- accessExpirationDate: PropTypes.PropTypes.instanceOf(Date).isRequired,
- timezoneFormatArgs: PropTypes.shape({
- timeZone: PropTypes.string,
- }),
- setupgradeNotificationCurrentState: PropTypes.func,
-};
-
-AccessExpirationDateBanner.defaultProps = {
- timezoneFormatArgs: {},
- setupgradeNotificationCurrentState: null,
-};
-
-const PastExpirationDateBanner = ({
- courseId, accessExpirationDate, timezoneFormatArgs, setupgradeNotificationCurrentState,
-}) => {
- if (setupgradeNotificationCurrentState) {
- setupgradeNotificationCurrentState('PastExpirationDate');
- setLocalStorage(`upgradeNotificationCurrentState.${courseId}`, 'PastExpirationDate');
- }
- return (
-
-
- ),
- }}
- />
-
- );
-};
-
-PastExpirationDateBanner.propTypes = {
- courseId: PropTypes.string.isRequired,
- accessExpirationDate: PropTypes.PropTypes.instanceOf(Date).isRequired,
- timezoneFormatArgs: PropTypes.shape({
- timeZone: PropTypes.string,
- }),
- setupgradeNotificationCurrentState: PropTypes.func,
-};
-
-PastExpirationDateBanner.defaultProps = {
- timezoneFormatArgs: {},
- setupgradeNotificationCurrentState: null,
-};
-
-const UpgradeNotification = ({
- accessExpiration,
- contentTypeGatingEnabled,
- marketingUrl,
- courseId,
- offer,
- org,
- setupgradeNotificationCurrentState,
- shouldDisplayBorder,
- timeOffsetMillis,
- upsellPageName,
- userTimezone,
- verifiedMode,
- toggleSidebar,
-}) => {
- const intl = useIntl();
- const dateNow = Date.now();
- const timezoneFormatArgs = userTimezone ? { timeZone: userTimezone } : {};
- const correctedTime = new Date(dateNow + timeOffsetMillis);
- const accessExpirationDate = accessExpiration ? new Date(accessExpiration.expirationDate) : null;
- const pastExpirationDeadline = accessExpiration ? new Date(dateNow) > accessExpirationDate : false;
-
- const eventProperties = {
- org_key: org,
- courserun_key: courseId,
- };
-
- const promotionEventProperties = {
- creative: 'sidebarupsell',
- name: 'In-Course Verification Prompt',
- position: 'sidebar-message',
- promotion_id: 'courseware_verified_certificate_upsell',
- ...eventProperties,
- };
-
- useEffect(() => {
- sendTrackingLogEvent('edx.bi.course.upgrade.sidebarupsell.displayed', eventProperties);
- sendTrackEvent('Promotion Viewed', promotionEventProperties);
- // eslint-disable-next-line react-hooks/exhaustive-deps
- }, []);
-
- if (!verifiedMode) {
- return null;
- }
-
- const logClick = () => {
- sendTrackingLogEvent('edx.bi.course.upgrade.sidebarupsell.clicked', eventProperties);
- sendTrackingLogEvent('edx.course.enrollment.upgrade.clicked', {
- ...eventProperties,
- location: 'sidebar-message',
- });
- sendTrackEvent('Promotion Clicked', promotionEventProperties);
- sendTrackEvent('edx.bi.ecommerce.upsell_links_clicked', {
- ...eventProperties,
- linkCategory: 'green_upgrade',
- linkName: `${upsellPageName}_green`,
- linkType: 'button',
- pageName: upsellPageName,
- });
- };
-
- const logClickPastExpiration = () => {
- sendTrackEvent('edx.bi.ecommerce.upgrade_notification.past_expiration.button_clicked', {
- ...eventProperties,
- linkCategory: 'upgrade_notification',
- linkName: `${upsellPageName}_course_details`,
- linkType: 'button',
- pageName: upsellPageName,
- });
- };
-
- /*
- There are 5 parts that change in the upgrade card:
- upgradeNotificationHeaderText
- expirationBanner
- upsellMessage
- callToActionButton
- offerCode
- */
- let upgradeNotificationHeaderText;
- let expirationBanner;
- let upsellMessage;
- let callToActionButton;
- let offerCode;
-
- if (!!accessExpiration && !!contentTypeGatingEnabled) {
- const hoursToAccessExpiration = Math.floor((accessExpirationDate - correctedTime) / 1000 / 60 / 60);
-
- if (hoursToAccessExpiration >= (7 * 24)) {
- if (offer) { // countdown to the first purchase discount if there is one
- const hoursToDiscountExpiration = Math.floor((new Date(offer.expirationDate) - correctedTime) / 1000 / 60 / 60);
- upgradeNotificationHeaderText = (
-
- );
- expirationBanner = (
-
- );
- } else {
- upgradeNotificationHeaderText = (
-
- );
- expirationBanner = (
-
- );
- }
- upsellMessage = ;
- } else if (hoursToAccessExpiration < (7 * 24) && hoursToAccessExpiration >= 0) {
- // more urgent messaging if there's less than 7 days left to access expiration
- upgradeNotificationHeaderText = (
-
- );
- expirationBanner = (
-
- );
- upsellMessage = (
-
- );
- } else { // access expiration deadline has passed
- upgradeNotificationHeaderText = (
-
- );
- expirationBanner = (
-
- );
- upsellMessage = (
-
- );
- }
- } else { // FBE is turned off
- upgradeNotificationHeaderText = (
-
- );
- upsellMessage = ();
- }
-
- if (pastExpirationDeadline) {
- callToActionButton = (
-
- );
- } else {
- callToActionButton = (
-
- );
- }
-
- if (offer) { // if there's a first purchase discount, message the code at the bottom
- offerCode = (
-
- {offer.code}),
- }}
- />
-
- );
- }
-
- return (
-
-
-
- {expirationBanner}
-
- {upsellMessage}
-
-
- {callToActionButton}
-
- {offerCode}
-
-
- );
-};
-
-UpgradeNotification.propTypes = {
- courseId: PropTypes.string.isRequired,
- org: PropTypes.string.isRequired,
- accessExpiration: PropTypes.shape({
- expirationDate: PropTypes.string,
- }),
- contentTypeGatingEnabled: PropTypes.bool,
- marketingUrl: PropTypes.string,
- offer: PropTypes.shape({
- expirationDate: PropTypes.string,
- percentage: PropTypes.number,
- code: PropTypes.string,
- }),
- toggleSidebar: PropTypes.func,
- shouldDisplayBorder: PropTypes.bool,
- setupgradeNotificationCurrentState: PropTypes.func,
- timeOffsetMillis: PropTypes.number,
- upsellPageName: PropTypes.string.isRequired,
- userTimezone: PropTypes.string,
- verifiedMode: PropTypes.shape({
- currencySymbol: PropTypes.string.isRequired,
- price: PropTypes.number.isRequired,
- upgradeUrl: PropTypes.string.isRequired,
- }),
-};
-
-UpgradeNotification.defaultProps = {
- accessExpiration: null,
- contentTypeGatingEnabled: false,
- marketingUrl: null,
- offer: null,
- setupgradeNotificationCurrentState: null,
- shouldDisplayBorder: null,
- timeOffsetMillis: 0,
- userTimezone: null,
- verifiedMode: null,
- toggleSidebar: null,
-};
-
-export default injectIntl(UpgradeNotification);
diff --git a/src/generic/upgrade-notification/UpgradeNotification.scss b/src/generic/upgrade-notification/UpgradeNotification.scss
deleted file mode 100644
index ee70643834..0000000000
--- a/src/generic/upgrade-notification/UpgradeNotification.scss
+++ /dev/null
@@ -1,46 +0,0 @@
-.upgrade-notification {
- border-radius: 0 !important;
-}
-
-.upgrade-notification-header {
- margin: 1.25rem;
-}
-
-.upsell-warning {
- background-color: $danger-100;
-}
-
-.upsell-warning-light {
- background-color: $warning-100;
-}
-
-.upsell-warning, .upsell-warning-light {
- padding: 0.5rem 1.25rem;
-}
-
-// .fa-ul added so specificity is higher than Font Awesome's .fa-ul.
-// An additional Font Awesome stylesheet is imported by Braze in
-// stage/production but not devstack.
-.upgrade-notification-ul.fa-ul {
- padding: 0.875rem 1.25rem 0;
- margin: 0 0 1rem 2.5rem;
-}
-
-.upgrade-notification-text {
- padding: 0.875rem 1.25rem 0 1.25rem;
-}
-
-.upgrade-notification-button {
- padding: 1.25rem;
- padding-top: 0;
-}
-
-.discount-info {
- border-top: 1px solid $light-400;
- padding-top: .75rem;
- padding-bottom: .75rem;
-}
-
-.font-size-18 {
- font-size: 18px !important;
-}
diff --git a/src/generic/upgrade-notification/UpgradeNotification.test.jsx b/src/generic/upgrade-notification/UpgradeNotification.test.jsx
deleted file mode 100644
index 8d97e4c10b..0000000000
--- a/src/generic/upgrade-notification/UpgradeNotification.test.jsx
+++ /dev/null
@@ -1,322 +0,0 @@
-import React from 'react';
-import { Factory } from 'rosie';
-import { sendTrackEvent } from '@edx/frontend-platform/analytics';
-
-import {
- fireEvent,
- initializeMockApp,
- render,
- screen,
- waitFor,
-} from '../../setupTest';
-import UpgradeNotification from './UpgradeNotification';
-
-initializeMockApp();
-jest.mock('@edx/frontend-platform/analytics');
-const dateNow = new Date('2021-04-13T11:01:58.000Z');
-jest
- .spyOn(global.Date, 'now')
- .mockImplementation(() => dateNow.valueOf());
-
-describe('Upgrade Notification', () => {
- function buildAndRender(attributes) {
- const upgradeNotificationData = Factory.build('upgradeNotificationData', { ...attributes });
- render();
- }
-
- it('sends upgrade click info to segment', async () => {
- sendTrackEvent.mockClear();
- buildAndRender({ pageName: 'test' });
-
- const upgradeButton = await waitFor(() => screen.queryByRole('link', { name: 'Upgrade for $149' }));
- fireEvent.click(upgradeButton);
-
- expect(sendTrackEvent).toHaveBeenCalledTimes(3);
- expect(sendTrackEvent).toHaveBeenNthCalledWith(3, 'edx.bi.ecommerce.upsell_links_clicked', {
- org_key: 'edX',
- courserun_key: 'course-v1:edX+DemoX+Demo_Course',
- linkCategory: 'green_upgrade',
- linkName: 'test_green',
- linkType: 'button',
- pageName: 'test',
- });
- });
-
- it('does not render when there is no verified mode', async () => {
- buildAndRender({ verifiedMode: null });
- expect(screen.queryByRole('link', { name: 'Upgrade for $149' })).not.toBeInTheDocument();
- });
-
- it('renders non-FBE when there is a verified mode but no FBE', async () => {
- buildAndRender();
- expect(screen.getByRole('heading', { name: 'Pursue a verified certificate' })).toBeInTheDocument();
- expect(screen.getByText(/Earn a.*?of completion to showcase on your resumé/s).textContent).toMatch('Earn a verified certificate of completion to showcase on your resumé');
- expect(screen.getByText(/Support our.*?at edX/s).textContent).toMatch('Support our mission at edX');
- expect(screen.getByRole('link', { name: 'Upgrade for $149' })).toBeInTheDocument();
- });
-
- it('renders non-FBE when there is a verified mode and access expiration, but no content gating', async () => {
- const expirationDate = new Date(dateNow);
- expirationDate.setMinutes(expirationDate.getMinutes() + 45);
- buildAndRender({
- accessExpiration: {
- expirationDate: expirationDate.toString(),
- },
- });
- expect(screen.getByRole('heading', { name: 'Pursue a verified certificate' })).toBeInTheDocument();
- expect(screen.getByText(/Earn a.*?of completion to showcase on your resumé/s).textContent).toMatch('Earn a verified certificate of completion to showcase on your resumé');
- expect(screen.getByText(/Support our.*?at edX/s).textContent).toMatch('Support our mission at edX');
- expect(screen.getByRole('link', { name: 'Upgrade for $149' })).toBeInTheDocument();
- });
-
- it('renders non-FBE when there is a verified mode and content gating, but no access expiration', async () => {
- buildAndRender({
- contentTypeGatingEnabled: true,
- accessExpiration: null,
- });
- expect(screen.getByRole('heading', { name: 'Pursue a verified certificate' })).toBeInTheDocument();
- expect(screen.getByText(/Earn a.*?of completion to showcase on your resumé/s).textContent).toMatch('Earn a verified certificate of completion to showcase on your resumé');
- expect(screen.getByText(/Support our.*?at edX/s).textContent).toMatch('Support our mission at edX');
- expect(screen.getByRole('link', { name: 'Upgrade for $149' })).toBeInTheDocument();
- });
-
- it('renders non-FBE with a discount properly', async () => {
- const discountExpirationDate = new Date(dateNow);
- discountExpirationDate.setDate(discountExpirationDate.getDate() + 6);
- buildAndRender({
- offer: {
- expirationDate: discountExpirationDate.toString(),
- percentage: 15,
- code: 'Welcome15',
- discountedPrice: '$126.65',
- originalPrice: '$149',
- upgradeUrl: 'www.exampleUpgradeUrl.com',
- },
- });
- expect(screen.getByRole('heading', { name: 'Pursue a verified certificate' })).toBeInTheDocument();
- expect(screen.getByText(/Earn a.*?of completion to showcase on your resumé/s).textContent).toMatch('Earn a verified certificate of completion to showcase on your resumé');
- expect(screen.getByText(/Support our.*?at edX/s).textContent).toMatch('Support our mission at edX');
- expect(screen.getByText(/Upgrade for/).textContent).toMatch('$126.65 ($149)');
- expect(screen.getByText(/Use code.*?at checkout/s).textContent).toMatch('Use code Welcome15 at checkout');
- });
-
- it('renders FBE expiration within an hour properly', async () => {
- const expirationDate = new Date(dateNow);
- expirationDate.setMinutes(expirationDate.getMinutes() + 45);
- buildAndRender({
- accessExpiration: {
- expirationDate: expirationDate.toString(),
- },
- contentTypeGatingEnabled: true,
- });
- expect(screen.getByRole('heading', { name: 'Course Access Expiration' })).toBeInTheDocument();
- expect(screen.getByText('Less than 1 hour left')).toBeInTheDocument();
- expect(screen.getByText(/You will lose all access to this course.*?on/s).textContent).toMatch('You will lose all access to this course, including any progress, on April 13.');
- expect(screen.getByText(/Upgrading your course enables you/s).textContent).toMatch('Upgrading your course enables you to pursue a verified certificate and unlocks numerous features. Learn more about the benefits of upgrading.');
- expect(screen.getByRole('link', { name: 'Upgrade for $149' })).toBeInTheDocument();
- });
-
- it('renders FBE expiration within 24 hours properly', async () => {
- const expirationDate = new Date(dateNow);
- expirationDate.setHours(expirationDate.getHours() + 12);
- buildAndRender({
- accessExpiration: {
- expirationDate: expirationDate.toString(),
- },
- contentTypeGatingEnabled: true,
- });
- expect(screen.getByRole('heading', { name: 'Course Access Expiration' })).toBeInTheDocument();
- expect(screen.getByText('12 hours left')).toBeInTheDocument();
- expect(screen.getByText(/You will lose all access to this course.*?on/s)).toHaveTextContent('You will lose all access to this course, including any progress, on April 13.');
- expect(screen.getByText(/Upgrading your course enables you/s).textContent).toMatch('Upgrading your course enables you to pursue a verified certificate and unlocks numerous features. Learn more about the benefits of upgrading.');
- expect(screen.getByRole('link', { name: 'Upgrade for $149' })).toBeInTheDocument();
- });
-
- it('renders FBE expiration within 7 days properly', async () => {
- const expirationDate = new Date(dateNow);
- expirationDate.setDate(expirationDate.getDate() + 6);
- buildAndRender({
- accessExpiration: {
- expirationDate: expirationDate.toString(),
- },
- contentTypeGatingEnabled: true,
- });
- expect(screen.getByRole('heading', { name: 'Course Access Expiration' })).toBeInTheDocument();
- expect(screen.getByText('6 days left')).toBeInTheDocument(); // setting the time to 12 will mean that it's slightly less than 12
- expect(screen.getByText(/You will lose all access to this course.*?on/s).textContent).toMatch('You will lose all access to this course, including any progress, on April 19.');
- expect(screen.getByText(/Upgrading your course enables you/s).textContent).toMatch('Upgrading your course enables you to pursue a verified certificate and unlocks numerous features. Learn more about the benefits of upgrading.');
- expect(screen.getByRole('link', { name: 'Upgrade for $149' })).toBeInTheDocument();
- });
-
- it('renders FBE expiration greater than 7 days properly', async () => {
- const expirationDate = new Date(dateNow);
- expirationDate.setDate(expirationDate.getDate() + 14);
- buildAndRender({
- accessExpiration: {
- expirationDate: expirationDate.toString(),
- },
- contentTypeGatingEnabled: true,
- });
- expect(screen.getByRole('heading', { name: 'Upgrade your course today' })).toBeInTheDocument();
- expect(screen.getByText(/Course access will expire/s).textContent).toMatch('Course access will expire April 27');
- expect(screen.getByText(/Earn a.*?of completion to showcase on your resumé/s).textContent).toMatch('Earn a verified certificate of completion to showcase on your resumé');
- expect(screen.getByText(/Unlock your access/s).textContent).toMatch('Unlock your access to all course activities, including graded assignments');
- expect(screen.getByText(/to course content and materials/s).textContent).toMatch('Full access to course content and materials, even after the course ends');
- expect(screen.getByText(/Support our.*?at edX/s).textContent).toMatch('Support our mission at edX');
- expect(screen.getByRole('link', { name: 'Upgrade for $149' })).toBeInTheDocument();
- });
-
- it('renders discount less than an hour properly', async () => {
- const accessExpirationDate = new Date(dateNow);
- accessExpirationDate.setDate(accessExpirationDate.getDate() + 21);
- const discountExpirationDate = new Date(dateNow);
- discountExpirationDate.setMinutes(discountExpirationDate.getMinutes() + 30);
- buildAndRender({
- accessExpiration: {
- expirationDate: accessExpirationDate.toString(),
- },
- contentTypeGatingEnabled: true,
- offer: {
- expirationDate: discountExpirationDate.toString(),
- percentage: 15,
- code: 'Welcome15',
- discountedPrice: '$126.65',
- originalPrice: '$149',
- upgradeUrl: 'www.exampleUpgradeUrl.com',
- },
- });
- expect(screen.getByRole('heading', { name: '15% First-Time Learner Discount' })).toBeInTheDocument();
- expect(screen.getByText('Less than 1 hour left')).toBeInTheDocument();
- expect(screen.getByText(/Earn a.*?of completion to showcase on your resumé/s).textContent).toMatch('Earn a verified certificate of completion to showcase on your resumé');
- expect(screen.getByText(/Unlock your access/s).textContent).toMatch('Unlock your access to all course activities, including graded assignments');
- expect(screen.getByText(/to course content and materials/s).textContent).toMatch('Full access to course content and materials, even after the course ends');
- expect(screen.getByText(/Support our.*?at edX/s).textContent).toMatch('Support our mission at edX');
- expect(screen.getByText(/Upgrade for/).textContent).toMatch('$126.65 ($149)');
- expect(screen.getByText(/Use code.*?at checkout/s).textContent).toMatch('Use code Welcome15 at checkout');
- });
-
- it('renders discount less than a day properly', async () => {
- const accessExpirationDate = new Date(dateNow);
- accessExpirationDate.setDate(accessExpirationDate.getDate() + 21);
- const discountExpirationDate = new Date(dateNow);
- discountExpirationDate.setHours(discountExpirationDate.getHours() + 12);
- buildAndRender({
- accessExpiration: {
- expirationDate: accessExpirationDate.toString(),
- },
- contentTypeGatingEnabled: true,
- offer: {
- expirationDate: discountExpirationDate.toString(),
- percentage: 15,
- code: 'Welcome15',
- discountedPrice: '$126.65',
- originalPrice: '$149',
- upgradeUrl: 'www.exampleUpgradeUrl.com',
- },
- });
- expect(screen.getByRole('heading', { name: '15% First-Time Learner Discount' })).toBeInTheDocument();
- expect(screen.getByText(/hours left/s).textContent).toMatch('12 hours left');
- expect(screen.getByText(/Earn a.*?of completion to showcase on your resumé/s).textContent).toMatch('Earn a verified certificate of completion to showcase on your resumé');
- expect(screen.getByText(/Unlock your access/s).textContent).toMatch('Unlock your access to all course activities, including graded assignments');
- expect(screen.getByText(/to course content and materials/s).textContent).toMatch('Full access to course content and materials, even after the course ends');
- expect(screen.getByText(/Support our.*?at edX/s).textContent).toMatch('Support our mission at edX');
- expect(screen.getByText(/Upgrade for/).textContent).toMatch('$126.65 ($149)');
- expect(screen.getByText(/Use code.*?at checkout/s).textContent).toMatch('Use code Welcome15 at checkout');
- });
-
- it('renders discount less a week properly', async () => {
- const accessExpirationDate = new Date(dateNow);
- accessExpirationDate.setDate(accessExpirationDate.getDate() + 21);
- const discountExpirationDate = new Date(dateNow);
- discountExpirationDate.setDate(discountExpirationDate.getDate() + 6);
- buildAndRender({
- accessExpiration: {
- expirationDate: accessExpirationDate.toString(),
- },
- contentTypeGatingEnabled: true,
- offer: {
- expirationDate: discountExpirationDate.toString(),
- percentage: 15,
- code: 'Welcome15',
- discountedPrice: '$126.65',
- originalPrice: '$149',
- upgradeUrl: 'www.exampleUpgradeUrl.com',
- },
- });
- expect(screen.getByRole('heading', { name: '15% First-Time Learner Discount' })).toBeInTheDocument();
- expect(screen.getByText(/days left/s).textContent).toMatch('6 days left');
- expect(screen.getByText(/Earn a.*?of completion to showcase on your resumé/s).textContent).toMatch('Earn a verified certificate of completion to showcase on your resumé');
- expect(screen.getByText(/Unlock your access/s).textContent).toMatch('Unlock your access to all course activities, including graded assignments');
- expect(screen.getByText(/to course content and materials/s).textContent).toMatch('Full access to course content and materials, even after the course ends');
- expect(screen.getByText(/Support our.*?at edX/s).textContent).toMatch('Support our mission at edX');
- expect(screen.getByText(/Upgrade for/).textContent).toMatch('$126.65 ($149)');
- expect(screen.getByText(/Use code.*?at checkout/s).textContent).toMatch('Use code Welcome15 at checkout');
- });
-
- it('renders discount less a week access expiration less than a week properly', async () => {
- const accessExpirationDate = new Date(dateNow);
- accessExpirationDate.setDate(accessExpirationDate.getDate() + 5);
- const discountExpirationDate = new Date(dateNow);
- discountExpirationDate.setDate(discountExpirationDate.getDate() + 6);
- buildAndRender({
- accessExpiration: {
- expirationDate: accessExpirationDate.toString(),
- },
- contentTypeGatingEnabled: true,
- offer: {
- expirationDate: discountExpirationDate.toString(),
- percentage: 15,
- code: 'Welcome15',
- discountedPrice: '$126.65',
- originalPrice: '$149',
- upgradeUrl: 'www.exampleUpgradeUrl.com',
- },
- });
- expect(screen.getByRole('heading', { name: 'Course Access Expiration' })).toBeInTheDocument();
- expect(screen.getByText('5 days left')).toBeInTheDocument(); // setting the time to 12 will mean that it's slightly less than 12
- expect(screen.getByText(/You will lose all access to this course.*?on/s).textContent).toMatch('You will lose all access to this course, including any progress, on April 18.');
- expect(screen.getByText(/Upgrading your course enables you/s).textContent).toMatch('Upgrading your course enables you to pursue a verified certificate and unlocks numerous features. Learn more about the benefits of upgrading.');
- expect(screen.getByText(/Upgrade for/).textContent).toMatch('$126.65 ($149)');
- expect(screen.getByText(/Use code.*?at checkout/s).textContent).toMatch('Use code Welcome15 at checkout');
- });
-
- it('renders past access expiration message properly', async () => {
- const expirationDate = new Date(dateNow);
- expirationDate.setDate(expirationDate.getDate() - 1);
- buildAndRender({
- contentTypeGatingEnabled: true,
- accessExpiration: {
- expirationDate: expirationDate.toString(),
- },
- });
- expect(screen.getByRole('heading', { name: 'Course Access Expiration' })).toBeInTheDocument();
- expect(screen.getByText(/The upgrade deadline/s).textContent).toMatch('The upgrade deadline for this course passed');
- expect(screen.getByText(/To upgrade/s).textContent).toMatch('To upgrade, enroll in the next available session');
- expect(screen.getByRole('button', { name: 'View Course Details' })).toBeInTheDocument();
- });
-
- it('sends course details click info to segment if past access expiration', async () => {
- const expirationDate = new Date(dateNow);
- expirationDate.setDate(expirationDate.getDate() - 1);
- sendTrackEvent.mockClear();
- buildAndRender({
- pageName: 'test',
- contentTypeGatingEnabled: true,
- accessExpiration: {
- expirationDate: expirationDate.toString(),
- },
- });
-
- const courseDetailsLink = await waitFor(() => screen.queryByRole('button', { name: 'View Course Details' }));
- fireEvent.click(courseDetailsLink);
- expect(sendTrackEvent).toHaveBeenCalledTimes(2);
- expect(sendTrackEvent).toHaveBeenNthCalledWith(2, 'edx.bi.ecommerce.upgrade_notification.past_expiration.button_clicked', {
- org_key: 'edX',
- courserun_key: 'course-v1:edX+DemoX+Demo_Course',
- linkCategory: 'upgrade_notification',
- linkName: 'test_course_details',
- linkType: 'button',
- pageName: 'test',
- });
- });
-});
diff --git a/src/generic/upsell-bullets/UpsellBullets.jsx b/src/generic/upsell-bullets/UpsellBullets.jsx
deleted file mode 100644
index e631ebae02..0000000000
--- a/src/generic/upsell-bullets/UpsellBullets.jsx
+++ /dev/null
@@ -1,105 +0,0 @@
-import React from 'react';
-import { faCheck } from '@fortawesome/free-solid-svg-icons';
-import { FontAwesomeIcon } from '@fortawesome/react-fontawesome';
-import { FormattedMessage } from '@edx/frontend-platform/i18n';
-import { getConfig } from '@edx/frontend-platform';
-
-const CheckmarkBullet = () => (
-
-);
-
-// Must be child of a
-export const VerifiedCertBullet = () => {
- const verifiedCertLink = (
-
-
-
- );
- return (
- -
-
-
-
- );
-};
-
-// Must be child of a
-export const UnlockGradedBullet = () => {
- const gradedAssignmentsInBoldText = (
-
-
-
- );
- return (
- -
-
-
-
- );
-};
-
-// Must be child of a
-export const FullAccessBullet = () => {
- const fullAccessInBoldText = (
-
-
-
- );
- return (
- -
-
-
-
- );
-};
-
-// Must be child of a
-export const SupportMissionBullet = () => {
- const missionInBoldText = (
-
-
-
- );
- return (
- -
-
-
-
- );
-};
diff --git a/src/generic/upsell-bullets/UpsellBullets.scss b/src/generic/upsell-bullets/UpsellBullets.scss
deleted file mode 100644
index 0cf75905b6..0000000000
--- a/src/generic/upsell-bullets/UpsellBullets.scss
+++ /dev/null
@@ -1,13 +0,0 @@
-.upsell-bullet > .fa-li {
- left: -31px;
- padding-right: 22px;
-}
-
-.inline-link-underline {
- text-decoration: underline;
-}
-
-.upsell-bullet a {
- color: $primary-500;
-}
-
diff --git a/src/generic/upsell-bullets/UpsellBullets.test.jsx b/src/generic/upsell-bullets/UpsellBullets.test.jsx
deleted file mode 100644
index daf7494378..0000000000
--- a/src/generic/upsell-bullets/UpsellBullets.test.jsx
+++ /dev/null
@@ -1,35 +0,0 @@
-import React from 'react';
-
-import {
- initializeMockApp,
- render,
- screen,
-} from '../../setupTest';
-
-import {
- VerifiedCertBullet,
- UnlockGradedBullet,
- FullAccessBullet,
- SupportMissionBullet,
-} from './UpsellBullets';
-
-initializeMockApp();
-
-describe('UpsellBullets', () => {
- const bullets = (
- <>
-
-
-
-
- >
- );
-
- it('upsell bullet text properly rendered', async () => {
- render(bullets);
- expect(screen.getByText(/Earn a.*?of completion to showcase on your resumé/s).textContent).toMatch('Earn a verified certificate of completion to showcase on your resumé');
- expect(screen.getByText(/Unlock your access/s).textContent).toMatch('Unlock your access to all course activities, including graded assignments');
- expect(screen.getByText(/to course content and materials/s).textContent).toMatch('Full access to course content and materials, even after the course ends');
- expect(screen.getByText(/Support our.*?at edX/s).textContent).toMatch('Support our mission at edX');
- });
-});
diff --git a/src/index.scss b/src/index.scss
index 6a72b32f97..4f445d65b0 100755
--- a/src/index.scss
+++ b/src/index.scss
@@ -433,13 +433,10 @@
// Import component-specific sass files
@import "courseware/course/celebration/CelebrationModal.scss";
@import "courseware/course/sidebar/sidebars/notifications/NotificationIcon.scss";
-@import "courseware/course/sequence/lock-paywall/LockPaywall.scss";
@import "shared/streak-celebration/StreakCelebrationModal.scss";
@import "courseware/course/content-tools/calculator/calculator.scss";
@import "courseware/course/content-tools/contentTools.scss";
@import "course-home/dates-tab/timeline/Day.scss";
-@import "generic/upgrade-notification/UpgradeNotification.scss";
-@import "generic/upsell-bullets/UpsellBullets.scss";
@import "course-home/outline-tab/widgets/ProctoringInfoPanel.scss";
@import "course-home/outline-tab/widgets/FlagButton.scss";
@import "course-home/progress-tab/course-completion/CompletionDonutChart.scss";