Rename Sidebar to NotificationTray

This commit is contained in:
julianajlk
2021-06-28 17:11:36 -04:00
parent 2f87b762f2
commit 1a5c6a8319
11 changed files with 88 additions and 88 deletions

View File

@@ -62,16 +62,16 @@ function Course({
);
// REV-2130 TODO: temporary cookie code that should be removed.
// In order to see the Value Prop sidebar in prod, a cookie should be set in
// In order to see the Value Prop Notification Tray in prod, a cookie should be set in
// the browser console and refresh: document.cookie = 'value_prop_cookie=true';
const isValuePropCookieSet = Cookies.get('value_prop_cookie') === 'true';
const shouldDisplayNotificationTrigger = useWindowSize().width >= responsiveBreakpoints.small.minWidth;
const [sidebarVisible, setSidebar] = useState(true);
const isSidebarVisible = () => sidebarVisible && setSidebar;
const toggleSidebar = () => {
if (sidebarVisible) { setSidebar(false); } else { setSidebar(true); }
const [notificationTrayVisible, setNotificationTray] = useState(true);
const isNotificationTrayVisible = () => notificationTrayVisible && setNotificationTray;
const toggleNotificationTray = () => {
if (notificationTrayVisible) { setNotificationTray(false); } else { setNotificationTray(true); }
};
/** [MM-P2P] Experiment */
@@ -104,8 +104,8 @@ function Course({
{ isValuePropCookieSet && shouldDisplayNotificationTrigger ? (
<NotificationTrigger
toggleSidebar={toggleSidebar}
isSidebarVisible={isSidebarVisible}
toggleNotificationTray={toggleNotificationTray}
isNotificationTrayVisible={isNotificationTrayVisible}
/>
) : null}
</div>
@@ -118,9 +118,9 @@ function Course({
unitNavigationHandler={unitNavigationHandler}
nextSequenceHandler={nextSequenceHandler}
previousSequenceHandler={previousSequenceHandler}
toggleSidebar={toggleSidebar}
isSidebarVisible={isSidebarVisible}
sidebarVisible={sidebarVisible}
toggleNotificationTray={toggleNotificationTray}
isNotificationTrayVisible={isNotificationTrayVisible}
notificationTrayVisible={notificationTrayVisible}
isValuePropCookieSet={isValuePropCookieSet}
//* * [MM-P2P] Experiment */
mmp2p={MMP2P}

View File

@@ -20,7 +20,7 @@ describe('Course', () => {
nextSequenceHandler: () => {},
previousSequenceHandler: () => {},
unitNavigationHandler: () => {},
toggleSidebar: () => {},
toggleNotificationTray: () => {},
};
beforeAll(async () => {
@@ -88,8 +88,8 @@ describe('Course', () => {
});
it('displays notification trigger', async () => {
const toggleSidebar = jest.fn();
const isSidebarVisible = jest.fn();
const toggleNotificationTray = jest.fn();
const isNotificationTrayVisible = jest.fn();
// REV-2130 TODO: remove cookie related code once temporary value prop cookie code is removed.
const cookieName = 'value_prop_cookie';
@@ -101,8 +101,8 @@ describe('Course', () => {
const testStore = await initializeTestStore({ courseMetadata, excludeFetchSequence: true }, false);
const testData = {
...mockData,
toggleSidebar,
isSidebarVisible,
toggleNotificationTray,
isNotificationTrayVisible,
};
render(<Course {...testData} courseId={courseMetadata.id} />, { store: testStore });

View File

@@ -11,8 +11,8 @@ import { useModel } from '../../generic/model-store';
import useWindowSize, { responsiveBreakpoints } from '../../generic/tabs/useWindowSize';
import UpgradeCard from '../../generic/upgrade-card/UpgradeCard';
function Sidebar({
intl, toggleSidebar,
function NotificationTray({
intl, toggleNotificationTray,
}) {
const {
courseId,
@@ -33,20 +33,20 @@ function Sidebar({
const shouldDisplayFullScreen = useWindowSize().width < responsiveBreakpoints.large.minWidth;
return (
<section className={classNames('sidebar-container ml-0 ml-lg-4', { 'no-notification': !verifiedMode && !shouldDisplayFullScreen })} aria-label={intl.formatMessage(messages.sidebarNotification)}>
<section className={classNames('notification-tray-container ml-0 ml-lg-4', { 'no-notification': !verifiedMode && !shouldDisplayFullScreen })} aria-label={intl.formatMessage(messages.notificationTray)}>
{shouldDisplayFullScreen ? (
<div className="mobile-close-container" onClick={() => { toggleSidebar(); }} onKeyDown={() => { toggleSidebar(); }} role="button" tabIndex="0" alt={intl.formatMessage(messages.responsiveCloseSidebar)}>
<div className="mobile-close-container" onClick={() => { toggleNotificationTray(); }} onKeyDown={() => { toggleNotificationTray(); }} role="button" tabIndex="0" alt={intl.formatMessage(messages.responsiveCloseNotificationTray)}>
<Icon src={ArrowBackIos} />
<span className="mobile-close">{intl.formatMessage(messages.responsiveCloseSidebar)}</span>
<span className="mobile-close">{intl.formatMessage(messages.responsiveCloseNotificationTray)}</span>
</div>
) : null}
<div className="sidebar-header px-3">
<div className="notification-tray-header px-3">
<span>{intl.formatMessage(messages.notificationTitle)}</span>
{shouldDisplayFullScreen
? null
: <Icon src={Close} className="close-btn" onClick={() => { toggleSidebar(); }} onKeyDown={() => { toggleSidebar(); }} role="button" tabIndex="0" alt={intl.formatMessage(messages.closeNotificationTrigger)} />}
: <Icon src={Close} className="close-btn" onClick={() => { toggleNotificationTray(); }} onKeyDown={() => { toggleNotificationTray(); }} role="button" tabIndex="0" alt={intl.formatMessage(messages.closeNotificationTrigger)} />}
</div>
<div className="sidebar-divider" />
<div className="notification-tray-divider" />
<div>{verifiedMode
? (
<UpgradeCard
@@ -60,19 +60,19 @@ function Sidebar({
org={org}
shouldDisplayBorder={false}
/>
) : <p className="sidebar-content">{intl.formatMessage(messages.noNotificationsMessage)}</p>}
) : <p className="notification-tray-content">{intl.formatMessage(messages.noNotificationsMessage)}</p>}
</div>
</section>
);
}
Sidebar.propTypes = {
NotificationTray.propTypes = {
intl: intlShape.isRequired,
toggleSidebar: PropTypes.func,
toggleNotificationTray: PropTypes.func,
};
Sidebar.defaultProps = {
toggleSidebar: null,
NotificationTray.defaultProps = {
toggleNotificationTray: null,
};
export default injectIntl(Sidebar);
export default injectIntl(NotificationTray);

View File

@@ -1,4 +1,4 @@
.sidebar-container {
.notification-tray-container {
border: 1px solid $light-400;
border-radius: 4px;
width: 31rem;
@@ -23,7 +23,7 @@
height: 15rem;
}
.sidebar-header {
.notification-tray-header {
padding: 0.625rem 0;
span {
@@ -35,7 +35,7 @@
float: right;
}
.sidebar-divider {
.notification-tray-divider {
width: 100.5%;
height: 0.5rem;
background: $gray-100;
@@ -43,7 +43,7 @@
border-left: 0;
}
.sidebar-content {
.notification-tray-content {
padding: 1rem;
font-size: 0.875rem;
}

View File

@@ -10,14 +10,14 @@ import {
} from '../../setupTest';
import initializeStore from '../../store';
import { appendBrowserTimezoneToUrl, executeThunk } from '../../utils';
import Sidebar from './Sidebar';
import NotificationTray from './NotificationTray';
import useWindowSize from '../../generic/tabs/useWindowSize';
initializeMockApp();
jest.mock('../../generic/tabs/useWindowSize');
jest.mock('@edx/frontend-platform/analytics');
describe('Sidebar', () => {
describe('NotificationTray', () => {
let mockData;
let axiosMock;
let store;
@@ -43,19 +43,19 @@ describe('Sidebar', () => {
axiosMock = new MockAdapter(getAuthenticatedHttpClient());
axiosMock.onGet(courseMetadataUrl).reply(200, defaultMetadata);
mockData = {
toggleSidebar: () => {},
toggleNotificationTray: () => {},
};
});
it('renders sidebar', async () => {
it('renders notification tray', async () => {
useWindowSize.mockReturnValue({ width: 1200, height: 422 });
await fetchAndRender(<Sidebar />);
await fetchAndRender(<NotificationTray />);
expect(screen.getByText('Notifications')).toBeInTheDocument();
expect(screen.queryByText('Back to course')).not.toBeInTheDocument();
});
it('renders upgrade card', async () => {
await fetchAndRender(<Sidebar />);
await fetchAndRender(<NotificationTray />);
const upgradeCard = document.querySelector('.upgrade-card');
expect(upgradeCard).toBeInTheDocument();
@@ -65,23 +65,23 @@ describe('Sidebar', () => {
it('renders no notifications message if no verified mode', async () => {
setMetadata({ verified_mode: null });
await fetchAndRender(<Sidebar />);
await fetchAndRender(<NotificationTray />);
expect(screen.queryByText('You have no new notifications at this time.')).toBeInTheDocument();
});
it('renders sidebar with full screen "Back to course" at response width', async () => {
it('renders notification tray with full screen "Back to course" at response width', async () => {
useWindowSize.mockReturnValue({ width: 991, height: 422 });
const toggleSidebar = jest.fn();
const toggleNotificationTray = jest.fn();
const testData = {
...mockData,
toggleSidebar,
toggleNotificationTray,
};
await fetchAndRender(<Sidebar {...testData} />);
await fetchAndRender(<NotificationTray {...testData} />);
const responsiveCloseButton = screen.getByRole('button', { name: 'Back to course' });
await waitFor(() => expect(responsiveCloseButton).toBeInTheDocument());
fireEvent.click(responsiveCloseButton);
expect(toggleSidebar).toHaveBeenCalledTimes(1);
expect(toggleNotificationTray).toHaveBeenCalledTimes(1);
});
});

View File

@@ -6,12 +6,12 @@ import { injectIntl, intlShape } from '@edx/frontend-platform/i18n';
import NotificationIcon from './NotificationIcon';
import messages from './messages';
function NotificationTrigger({ intl, toggleSidebar, isSidebarVisible }) {
function NotificationTrigger({ intl, toggleNotificationTray, isNotificationTrayVisible }) {
return (
<button
className={classNames('notification-trigger-btn', { active: isSidebarVisible() })}
className={classNames('notification-trigger-btn', { active: isNotificationTrayVisible() })}
type="button"
onClick={() => { toggleSidebar(); }}
onClick={() => { toggleNotificationTray(); }}
aria-label={intl.formatMessage(messages.openNotificationTrigger)}
>
{/* REV-2130 TODO: add logic for status "active" if red dot should display */}
@@ -22,8 +22,8 @@ function NotificationTrigger({ intl, toggleSidebar, isSidebarVisible }) {
NotificationTrigger.propTypes = {
intl: intlShape.isRequired,
toggleSidebar: PropTypes.func.isRequired,
isSidebarVisible: PropTypes.func.isRequired,
toggleNotificationTray: PropTypes.func.isRequired,
isNotificationTrayVisible: PropTypes.func.isRequired,
};
export default injectIntl(NotificationTrigger);

View File

@@ -12,8 +12,8 @@ describe('Notification Trigger', () => {
beforeAll(async () => {
await initializeTestStore({ courseMetadata, excludeFetchCourse: true, excludeFetchSequence: true });
mockData = {
toggleSidebar: () => {},
isSidebarVisible: () => {},
toggleNotificationTray: () => {},
isNotificationTrayVisible: () => {},
};
});
@@ -27,17 +27,17 @@ describe('Notification Trigger', () => {
expect(screen.getByTestId('notification-dot')).toBeInTheDocument();
});
it('handles onClick event toggling the sidebar', async () => {
const toggleSidebar = jest.fn();
it('handles onClick event toggling the notification tray', async () => {
const toggleNotificationTray = jest.fn();
const testData = {
...mockData,
toggleSidebar,
toggleNotificationTray,
};
render(<NotificationTrigger {...testData} />);
const notificationOpenButton = screen.getByRole('button', { name: /Show notification tray/i });
expect(notificationOpenButton).toBeInTheDocument();
fireEvent.click(notificationOpenButton);
expect(toggleSidebar).toHaveBeenCalledTimes(1);
expect(toggleNotificationTray).toHaveBeenCalledTimes(1);
});
});

View File

@@ -1,10 +1,10 @@
import { defineMessages } from '@edx/frontend-platform/i18n';
const messages = defineMessages({
sidebarNotification: {
id: 'sidebar.notification.container',
defaultMessage: 'Sidebar notification',
description: 'Sidebar notification section container',
notificationTray: {
id: 'notification.tray.container',
defaultMessage: 'Notification tray',
description: 'Notification tray container',
},
openNotificationTrigger: {
id: 'notification.open.button',
@@ -13,21 +13,21 @@ const messages = defineMessages({
},
closeNotificationTrigger: {
id: 'notification.close.button',
defaultMessage: 'Close sidebar notification',
description: 'Button for the learner to close the sidebar',
defaultMessage: 'Close notification tray',
description: 'Button to close the notification tray',
},
responsiveCloseSidebar: {
id: 'sidebar.responsive.close.button',
responsiveCloseNotificationTray: {
id: 'responsive.close.notification',
defaultMessage: 'Back to course',
description: 'Responsive button for the learner to go back to course and close the sidebar',
description: 'Responsive button to go back to course and close the notification tray',
},
notificationTitle: {
id: 'sidebar.notification.title',
id: 'notification.tray.title',
defaultMessage: 'Notifications',
description: 'Title text displayed for sidebar notifications',
description: 'Title text displayed for the notification tray',
},
noNotificationsMessage: {
id: 'sidebar.notification.no.message',
id: 'notification.tray.no.message',
defaultMessage: 'You have no new notifications at this time.',
description: 'Text displayed when the learner has no notifications',
},

View File

@@ -22,7 +22,7 @@ import CourseLicense from '../course-license';
import messages from './messages';
import { SequenceNavigation, UnitNavigation } from './sequence-navigation';
import SequenceContent from './SequenceContent';
import Sidebar from '../Sidebar';
import NotificationTray from '../NotificationTray';
import NotificationTrigger from '../NotificationTrigger';
/** [MM-P2P] Experiment */
@@ -37,9 +37,9 @@ function Sequence({
nextSequenceHandler,
previousSequenceHandler,
intl,
toggleSidebar,
sidebarVisible,
isSidebarVisible,
toggleNotificationTray,
notificationTrayVisible,
isNotificationTrayVisible,
isValuePropCookieSet,
mmp2p,
}) {
@@ -194,8 +194,8 @@ function Sequence({
{isValuePropCookieSet && shouldDisplayNotificationTrigger ? (
<NotificationTrigger
toggleSidebar={toggleSidebar}
isSidebarVisible={isSidebarVisible}
toggleNotificationTray={toggleNotificationTray}
isNotificationTrayVisible={isNotificationTrayVisible}
/>
) : null}
@@ -226,10 +226,10 @@ function Sequence({
)}
</div>
</div>
{isValuePropCookieSet && sidebarVisible ? (
<Sidebar
toggleSidebar={toggleSidebar}
sidebarVisible={sidebarVisible}
{isValuePropCookieSet && notificationTrayVisible ? (
<NotificationTray
toggleNotificationTray={toggleNotificationTray}
notificationTrayVisible={notificationTrayVisible}
/>
) : null }
@@ -269,9 +269,9 @@ Sequence.propTypes = {
nextSequenceHandler: PropTypes.func.isRequired,
previousSequenceHandler: PropTypes.func.isRequired,
intl: intlShape.isRequired,
toggleSidebar: PropTypes.func,
sidebarVisible: PropTypes.bool,
isSidebarVisible: PropTypes.func,
toggleNotificationTray: PropTypes.func,
notificationTrayVisible: PropTypes.bool,
isNotificationTrayVisible: PropTypes.func,
isValuePropCookieSet: PropTypes.bool,
/** [MM-P2P] Experiment */
@@ -291,9 +291,9 @@ Sequence.propTypes = {
Sequence.defaultProps = {
sequenceId: null,
unitId: null,
toggleSidebar: null,
sidebarVisible: null,
isSidebarVisible: null,
toggleNotificationTray: null,
notificationTrayVisible: null,
isNotificationTrayVisible: null,
isValuePropCookieSet: null,
/** [MM-P2P] Experiment */

View File

@@ -28,7 +28,7 @@ describe('Sequence', () => {
unitNavigationHandler: () => {},
nextSequenceHandler: () => {},
previousSequenceHandler: () => {},
sidebarVisible: false,
notificationTrayVisible: false,
};
});
@@ -130,10 +130,10 @@ describe('Sequence', () => {
expect(screen.getAllByRole('button', { name: /previous|next/i }).length).toEqual(4);
});
it('renders sidebar in sequence', async () => {
it('renders notification tray in sequence', async () => {
const testData = {
...mockData,
sidebarVisible: true,
notificationTrayVisible: true,
isValuePropCookieSet: true,
};

View File

@@ -372,7 +372,7 @@
// Import component-specific sass files
@import 'courseware/course/celebration/CelebrationModal.scss';
@import 'courseware/course/Sidebar.scss';
@import 'courseware/course/NotificationTray.scss';
@import 'courseware/course/NotificationTrigger.scss';
@import 'courseware/course/NotificationIcon.scss';
@import 'shared/streak-celebration/StreakCelebrationModal.scss';