-
Notifications
You must be signed in to change notification settings - Fork 215
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
feat: generic sidebar notification plugin #1379
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -124,20 +124,6 @@ const OutlineTab = ({ intl }) => { | |
} | ||
}, [location.search]); | ||
|
||
const upgradeNotificationProps = { | ||
offer, | ||
verifiedMode, | ||
accessExpiration, | ||
contentTypeGatingEnabled: datesBannerInfo.contentTypeGatingEnabled, | ||
marketingUrl, | ||
upsellPageName: 'course_home', | ||
userTimezone, | ||
timeOffsetMillis, | ||
courseId, | ||
org, | ||
shouldDisplayBorder: true, | ||
}; | ||
|
||
return ( | ||
<> | ||
<div data-learner-type={learnerType} className="row w-100 mx-0 my-3 justify-content-between"> | ||
|
@@ -210,11 +196,22 @@ const OutlineTab = ({ intl }) => { | |
)} | ||
<CourseTools /> | ||
<PluginSlot | ||
id="outline_tab" | ||
pluginProps={upgradeNotificationProps} | ||
testId="outline-tab-slot" | ||
id="outline_tab_notifications_plugin" | ||
pluginProps={{ courseId }} | ||
> | ||
<UpgradeNotification {...upgradeNotificationProps} /> | ||
<UpgradeNotification | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. revert back to what's in main today, no change in behavior if the plugin is off. |
||
offer={offer} | ||
verifiedMode={verifiedMode} | ||
accessExpiration={accessExpiration} | ||
contentTypeGatingEnabled={datesBannerInfo.contentTypeGatingEnabled} | ||
marketingUrl={marketingUrl} | ||
upsellPageName="course_home" | ||
userTimezone={userTimezone} | ||
shouldDisplayBorder | ||
timeOffsetMillis={timeOffsetMillis} | ||
courseId={courseId} | ||
org={org} | ||
/> | ||
</PluginSlot> | ||
<CourseDates /> | ||
<CourseHandouts /> | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -80,7 +80,7 @@ describe('NotificationsWidget', () => { | |
}); | ||
}); | ||
|
||
it('renders upgrade card', async () => { | ||
it('includes notification_widget_plugin slot', async () => { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. for this and other components I split testing the plugin slot and behavior of the default content w/o a plugin since we expect the latter to be removed. |
||
await fetchAndRender( | ||
<SidebarContext.Provider value={{ | ||
currentSidebar: ID, | ||
|
@@ -92,12 +92,24 @@ describe('NotificationsWidget', () => { | |
<NotificationsWidget /> | ||
</SidebarContext.Provider>, | ||
); | ||
expect(screen.getByTestId('notification_widget_plugin')).toBeInTheDocument(); | ||
}); | ||
|
||
const pluginSlot = screen.getByTestId('notification-widget-slot'); | ||
expect(pluginSlot).toBeInTheDocument(); | ||
it('renders upgrade card', async () => { | ||
await fetchAndRender( | ||
<SidebarContext.Provider value={{ | ||
currentSidebar: ID, | ||
courseId, | ||
hideNotificationbar: false, | ||
isNotificationbarAvailable: true, | ||
}} | ||
> | ||
<NotificationsWidget /> | ||
</SidebarContext.Provider>, | ||
); | ||
|
||
// The Upgrade Notification should be inside the PluginSlot. | ||
const UpgradeNotification = pluginSlot.querySelector('.upgrade-notification'); | ||
const UpgradeNotification = document.querySelector('.upgrade-notification'); | ||
expect(UpgradeNotification).toBeInTheDocument(); | ||
|
||
expect(screen.getByRole('link', { name: 'Upgrade for $149' })).toBeInTheDocument(); | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -66,22 +66,6 @@ const NotificationTray = ({ intl }) => { | |
sendTrackEvent('edx.ui.course.upgrade.old_sidebar.notifications', notificationTrayEventProperties); | ||
}, []); | ||
|
||
const upgradeNotificationProps = { | ||
offer, | ||
verifiedMode, | ||
accessExpiration, | ||
contentTypeGatingEnabled, | ||
marketingUrl, | ||
upsellPageName: 'in_course', | ||
userTimezone, | ||
shouldDisplayBorder: false, | ||
timeOffsetMillis, | ||
courseId, | ||
org, | ||
upgradeNotificationCurrentState, | ||
setupgradeNotificationCurrentState: setUpgradeNotificationCurrentState, // TODO: Check typo in component? | ||
}; | ||
|
||
return ( | ||
<SidebarBase | ||
title={intl.formatMessage(messages.notificationTitle)} | ||
|
@@ -93,11 +77,28 @@ const NotificationTray = ({ intl }) => { | |
<div>{verifiedMode | ||
? ( | ||
<PluginSlot | ||
id="notification_tray" | ||
pluginProps={upgradeNotificationProps} | ||
testId="notification-tray-slot" | ||
id="notification_tray_plugin" | ||
pluginProps={{ | ||
courseId, | ||
notificationCurrentState: upgradeNotificationCurrentState, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. This drives the 'red dot' notification icon. I've removed the 'upgrade' from how this is passed to the plugin to keep it general. On the learning MFE side all the variables relating to this are still called 'upgrade...' we should rename all of that eventually. Probably at the same time we remove all the upgrade code from the learning MFE. I think these would belong on the API for this plugin slot since any plugin here may want to drive that icon. That said, the code for the red dot is tightly coupled to upgrade right now but you could use it creatively for other purposes. It would probably take further consideration on how we handle notifications from multiple sources (if you put more than 1 plugin here) when the need arises. My thinking is the existence of a getter/setter wouldn't need to change so what I have here should be a stable interface. |
||
setNotificationCurrentState: setUpgradeNotificationCurrentState, | ||
}} | ||
> | ||
<UpgradeNotification {...upgradeNotificationProps} /> | ||
<UpgradeNotification | ||
offer={offer} | ||
verifiedMode={verifiedMode} | ||
accessExpiration={accessExpiration} | ||
contentTypeGatingEnabled={contentTypeGatingEnabled} | ||
marketingUrl={marketingUrl} | ||
upsellPageName="in_course" | ||
userTimezone={userTimezone} | ||
shouldDisplayBorder={false} | ||
timeOffsetMillis={timeOffsetMillis} | ||
courseId={courseId} | ||
org={org} | ||
upgradeNotificationCurrentState={upgradeNotificationCurrentState} | ||
setupgradeNotificationCurrentState={setUpgradeNotificationCurrentState} | ||
/> | ||
</PluginSlot> | ||
) : ( | ||
<p className="p-3 small">{intl.formatMessage(messages.noNotificationsMessage)}</p> | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,11 +1,12 @@ | ||
import React from 'react'; | ||
import PropTypes from 'prop-types'; | ||
|
||
const MockedPluginSlot = ({ children, testId }) => { | ||
if (!testId) { return children ?? 'PluginSlot'; } // Return its content if PluginSlot slot is wrapping any. | ||
|
||
return <div data-testid={testId}>{children}</div>; | ||
}; | ||
const MockedPluginSlot = ({ children, id }) => ( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I had to modify how this works a bit because we get react errors if |
||
<div data-testid={id}> | ||
PluginSlot_{id} | ||
{ children && <div>{children}</div> } | ||
</div> | ||
); | ||
|
||
MockedPluginSlot.displayName = 'PluginSlot'; | ||
|
||
|
@@ -14,12 +15,12 @@ MockedPluginSlot.propTypes = { | |
PropTypes.arrayOf(PropTypes.node), | ||
PropTypes.node, | ||
]), | ||
testId: PropTypes.string, | ||
id: PropTypes.string, | ||
}; | ||
|
||
MockedPluginSlot.defaultProps = { | ||
children: undefined, | ||
testId: undefined, | ||
id: undefined, | ||
}; | ||
|
||
export default MockedPluginSlot; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
changed the name on these to align convention with existing plugins
xxxxx_plugin