forked from deriv-com/deriv-app
-
Notifications
You must be signed in to change notification settings - Fork 1
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request #60 from shaheer-deriv/shaheer/WALL-1489
refactor: 🎨 moves notification components to separate files
- Loading branch information
Showing
16 changed files
with
549 additions
and
281 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
2 changes: 1 addition & 1 deletion
2
...ages/core/src/App/Components/Elements/Notifications/__tests__/empty-notification.spec.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -31,4 +31,4 @@ const EmptyNotification = () => ( | |
</div> | ||
); | ||
|
||
export { EmptyNotification }; | ||
export default EmptyNotification; |
62 changes: 62 additions & 0 deletions
62
.../core/src/App/Containers/NotificationsDialog/__tests__/notification-list-wrapper.spec.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
import React from 'react'; | ||
import { StoreProvider, mockStore } from '@deriv/stores'; | ||
import { render, screen } from '@testing-library/react'; | ||
import NotificationListWrapper from '../notification-list-wrapper'; | ||
|
||
jest.mock('App/Components/Routes', () => ({ BinaryLink: 'MockedBinaryLink' })); | ||
|
||
describe('NotificationListWrapper', () => { | ||
const mock_store_without_notifications = mockStore({ notifications: { notifications: [] } }); | ||
const mock_store_with_notifications = mockStore({ | ||
notifications: { | ||
notifications: [ | ||
{ | ||
key: 'mock_notification_key', | ||
header: 'Mock Notification Header', | ||
message: 'Mock Notification Message', | ||
action: { | ||
route: '/mock/route', | ||
text: 'Mock Notification Action', | ||
}, | ||
type: 'mock_notification_type', | ||
}, | ||
], | ||
}, | ||
}); | ||
const renderComponent = (mock_store = mockStore({})) => { | ||
const mock_props = { clearNotifications: jest.fn() }; | ||
render( | ||
<StoreProvider store={mock_store}> | ||
<NotificationListWrapper {...mock_props} /> | ||
</StoreProvider> | ||
); | ||
}; | ||
|
||
it('should render the component', () => { | ||
renderComponent(mock_store_without_notifications); | ||
expect(screen.getByTestId('dt_notifications_list_wrapper')).toBeInTheDocument(); | ||
}); | ||
|
||
it('should render the "EmptyNotification" component if notifications list is empty', () => { | ||
renderComponent(mock_store_without_notifications); | ||
expect(screen.getByText('No notifications')).toBeInTheDocument(); | ||
expect(screen.getByText('You have yet to receive any notifications')).toBeInTheDocument(); | ||
expect(screen.queryByText('Mock Notification Header')).not.toBeInTheDocument(); | ||
expect(screen.queryByText('Mock Notification Message')).not.toBeInTheDocument(); | ||
expect(screen.queryByText('Mock Notification Action')).not.toBeInTheDocument(); | ||
}); | ||
|
||
it('should render the "NotificationsList" component if notifications list is not empty', () => { | ||
renderComponent(mock_store_with_notifications); | ||
expect(screen.getByText('Mock Notification Header')).toBeInTheDocument(); | ||
expect(screen.getByText('Mock Notification Message')).toBeInTheDocument(); | ||
expect(screen.getByText('Mock Notification Action')).toBeInTheDocument(); | ||
expect(screen.queryByText('No notifications')).not.toBeInTheDocument(); | ||
expect(screen.queryByText('You have yet to receive any notifications')).not.toBeInTheDocument(); | ||
}); | ||
|
||
it('should render the "ClearAllFooter" component', () => { | ||
renderComponent(mock_store_without_notifications); | ||
expect(screen.getByText('Clear All')).toBeInTheDocument(); | ||
}); | ||
}); |
72 changes: 72 additions & 0 deletions
72
.../src/App/Containers/NotificationsDialog/__tests__/notifications-clear-all-footer.spec.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,72 @@ | ||
import React from 'react'; | ||
import { StoreProvider, mockStore } from '@deriv/stores'; | ||
import { fireEvent, render, screen } from '@testing-library/react'; | ||
import ClearAllFooter from '../notifications-clear-all-footer'; | ||
|
||
describe('ClearAllFooter', () => { | ||
const mock_store_without_notifications = mockStore({ notifications: { notifications: [] } }); | ||
const mock_store_with_notifications = mockStore({ | ||
notifications: { | ||
notifications: [ | ||
{ | ||
key: 'mock_security_notification', | ||
header: 'Stronger security for your Deriv account', | ||
message: | ||
'With two-factor authentication, you’ll protect your account with both your password and your phone - so only you can access your account, even if someone knows your password.', | ||
action: { | ||
route: '/account/two-factor-authentication', | ||
text: 'Secure my account', | ||
}, | ||
type: 'warning', | ||
}, | ||
], | ||
}, | ||
}); | ||
const mock_props: React.ComponentProps<typeof ClearAllFooter> = { clearNotifications: jest.fn() }; | ||
|
||
it('should render the component', () => { | ||
render( | ||
<StoreProvider store={mock_store_without_notifications}> | ||
<ClearAllFooter {...mock_props} /> | ||
</StoreProvider> | ||
); | ||
expect(screen.getByTestId('dt_clear_all_footer_button')).toBeInTheDocument(); | ||
}); | ||
|
||
it('should render the button', () => { | ||
render( | ||
<StoreProvider store={mock_store_without_notifications}> | ||
<ClearAllFooter {...mock_props} /> | ||
</StoreProvider> | ||
); | ||
expect(screen.getByRole('button', { name: 'Clear All' })).toBeInTheDocument(); | ||
}); | ||
|
||
it('should render the button in disabled state if there are no notifications', () => { | ||
render( | ||
<StoreProvider store={mock_store_without_notifications}> | ||
<ClearAllFooter {...mock_props} /> | ||
</StoreProvider> | ||
); | ||
expect(screen.getByRole('button', { name: 'Clear All' })).toBeDisabled(); | ||
}); | ||
|
||
it('should render the button in enabled state if there are notifications available', () => { | ||
render( | ||
<StoreProvider store={mock_store_with_notifications}> | ||
<ClearAllFooter {...mock_props} /> | ||
</StoreProvider> | ||
); | ||
expect(screen.getByRole('button', { name: 'Clear All' })).toBeEnabled(); | ||
}); | ||
|
||
it('should fire the "clearNotifications" method on clicking the button', () => { | ||
render( | ||
<StoreProvider store={mock_store_with_notifications}> | ||
<ClearAllFooter {...mock_props} /> | ||
</StoreProvider> | ||
); | ||
fireEvent.click(screen.getByRole('button', { name: 'Clear All' })); | ||
expect(mock_props.clearNotifications).toBeCalledTimes(1); | ||
}); | ||
}); |
59 changes: 59 additions & 0 deletions
59
packages/core/src/App/Containers/NotificationsDialog/__tests__/notifications-dialog.spec.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,59 @@ | ||
import React from 'react'; | ||
import { isDesktop, isMobile } from '@deriv/shared'; | ||
import { StoreProvider, mockStore } from '@deriv/stores'; | ||
import { render, screen } from '@testing-library/react'; | ||
import NotificationsDialog from '../notifications-dialog'; | ||
|
||
jest.mock('react-transition-group', () => ({ CSSTransition: () => 'MockedCSSTransition' })); | ||
jest.mock('@deriv/components', () => ({ | ||
...jest.requireActual('@deriv/components'), | ||
MobileDialog: () => 'MockedMobileDialog', | ||
})); | ||
jest.mock('@deriv/shared', () => ({ | ||
...jest.requireActual('@deriv/shared'), | ||
isDesktop: jest.fn(() => true), | ||
isMobile: jest.fn(() => false), | ||
})); | ||
|
||
describe('NotificationsDialog', () => { | ||
const renderComponent = (mock_store_override = {}) => { | ||
const mock_store = mockStore({ | ||
notifications: { | ||
is_notifications_visible: true, | ||
notifications: [ | ||
{ | ||
key: 'mock_notification_key', | ||
header: 'Mock Notification Header', | ||
message: 'Mock Notification Message', | ||
action: { | ||
route: '/mock/route', | ||
text: 'Mock Notification Action', | ||
}, | ||
type: 'mock_notification_type', | ||
}, | ||
], | ||
toggleNotificationsModal: jest.fn(), | ||
}, | ||
...mock_store_override, | ||
}); | ||
render( | ||
<StoreProvider store={mock_store}> | ||
<NotificationsDialog /> | ||
</StoreProvider> | ||
); | ||
}; | ||
|
||
it('should render the component CSSTranition in desktop mode', () => { | ||
renderComponent(); | ||
expect(screen.getByText('MockedCSSTransition')).toBeInTheDocument(); | ||
expect(screen.queryByText('MockedMobileDialog')).not.toBeInTheDocument(); | ||
}); | ||
|
||
it('should render the component MobileDialog in mobile mode', () => { | ||
(isDesktop as jest.Mock).mockReturnValue(false); | ||
(isMobile as jest.Mock).mockReturnValue(true); | ||
renderComponent(); | ||
expect(screen.getByText('MockedMobileDialog')).toBeInTheDocument(); | ||
expect(screen.queryByText('MockedCSSTransition')).not.toBeInTheDocument(); | ||
}); | ||
}); |
49 changes: 49 additions & 0 deletions
49
packages/core/src/App/Containers/NotificationsDialog/__tests__/notifications-list.spec.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,49 @@ | ||
import React from 'react'; | ||
import { StoreProvider, mockStore } from '@deriv/stores'; | ||
import { render, screen } from '@testing-library/react'; | ||
import NotificationsList from '../notifications-list'; | ||
|
||
jest.mock('App/Components/Routes', () => ({ BinaryLink: 'MockedBinaryLink' })); | ||
|
||
describe('NotificationsList', () => { | ||
const renderComponent = (mock_store_override = {}) => { | ||
const mock_store = mockStore({ | ||
notifications: { | ||
notifications: [ | ||
{ | ||
key: 'mock_notification_key', | ||
header: 'Mock Notification Header', | ||
message: 'Mock Notification Message', | ||
action: { | ||
route: '/mock/route', | ||
text: 'Mock Notification Action', | ||
}, | ||
type: 'mock_notification_type', | ||
}, | ||
], | ||
toggleNotificationsModal: jest.fn(), | ||
}, | ||
...mock_store_override, | ||
}); | ||
render( | ||
<StoreProvider store={mock_store}> | ||
<NotificationsList /> | ||
</StoreProvider> | ||
); | ||
}; | ||
|
||
it('should render the notification header', () => { | ||
renderComponent(); | ||
expect(screen.getByText('Mock Notification Header')).toBeInTheDocument(); | ||
}); | ||
|
||
it('should render the notification message', () => { | ||
renderComponent(); | ||
expect(screen.getByText('Mock Notification Message')).toBeInTheDocument(); | ||
}); | ||
|
||
it('should render the notification action button', () => { | ||
renderComponent(); | ||
expect(screen.getByText('Mock Notification Action')).toBeInTheDocument(); | ||
}); | ||
}); |
3 changes: 0 additions & 3 deletions
3
packages/core/src/App/Containers/NotificationsDialog/index.js
This file was deleted.
Oops, something went wrong.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1 @@ | ||
export { default } from './notifications-dialog'; |
62 changes: 62 additions & 0 deletions
62
packages/core/src/App/Containers/NotificationsDialog/notification-list-wrapper.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,62 @@ | ||
import classNames from 'classnames'; | ||
import React, { LegacyRef } from 'react'; | ||
import { Text, ThemedScrollbars } from '@deriv/components'; | ||
import { isMobile, routes } from '@deriv/shared'; | ||
import { observer, useStore } from '@deriv/stores'; | ||
import { Localize } from '@deriv/translations'; | ||
import EmptyNotification from 'App/Components/Elements/Notifications/empty-notification'; | ||
import ClearAllFooter from './notifications-clear-all-footer'; | ||
import NotificationsList from './notifications-list'; | ||
|
||
type TNotificationListWrapper = { clearNotifications: () => void }; | ||
|
||
const NotificationListWrapperForwardRef = React.forwardRef( | ||
({ clearNotifications }: TNotificationListWrapper, ref: LegacyRef<HTMLDivElement> | undefined) => { | ||
const { notifications } = useStore(); | ||
const { notifications: notifications_array } = notifications; | ||
const is_empty = !notifications_array?.length; | ||
|
||
const traders_hub = window.location.pathname === routes.traders_hub; | ||
|
||
return ( | ||
<div | ||
data-testid='dt_notifications_list_wrapper' | ||
className={classNames('notifications-dialog', { | ||
'notifications-dialog--pre-appstore': | ||
traders_hub || window.location.pathname.startsWith(routes.account), | ||
})} | ||
ref={ref} | ||
> | ||
<div className='notifications-dialog__header'> | ||
<Text | ||
as='h2' | ||
className='notifications-dialog__header-text' | ||
size='s' | ||
weight='bold' | ||
color='prominent' | ||
styles={{ | ||
lineHeight: '1.6rem', | ||
}} | ||
> | ||
<Localize i18n_default_text='Notifications' /> | ||
</Text> | ||
</div> | ||
<div | ||
className={classNames('notifications-dialog__content', { | ||
'notifications-dialog__content--empty': is_empty, | ||
})} | ||
> | ||
<ThemedScrollbars is_bypassed={isMobile() || is_empty}> | ||
{is_empty ? <EmptyNotification /> : <NotificationsList />} | ||
</ThemedScrollbars> | ||
</div> | ||
<ClearAllFooter clearNotifications={clearNotifications} /> | ||
</div> | ||
); | ||
} | ||
); | ||
NotificationListWrapperForwardRef.displayName = 'NotificationListWrapper'; | ||
|
||
const NotificationListWrapper = observer(NotificationListWrapperForwardRef); | ||
|
||
export default NotificationListWrapper; |
41 changes: 41 additions & 0 deletions
41
packages/core/src/App/Containers/NotificationsDialog/notifications-clear-all-footer.tsx
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,41 @@ | ||
import React from 'react'; | ||
import classNames from 'classnames'; | ||
import { Button, Text } from '@deriv/components'; | ||
import { isMobile } from '@deriv/shared'; | ||
import { localize } from '@deriv/translations'; | ||
import { observer, useStore } from '@deriv/stores'; | ||
|
||
type TClearAllFooter = { | ||
clearNotifications: () => void; | ||
}; | ||
|
||
const ClearAllFooter = observer(({ clearNotifications }: TClearAllFooter) => { | ||
const { notifications } = useStore(); | ||
const { notifications: notifications_array } = notifications; | ||
const is_empty = !notifications_array?.length; | ||
|
||
return ( | ||
<React.Fragment> | ||
<div className='notifications-dialog__separator' /> | ||
<div | ||
data-testid='dt_clear_all_footer_button' | ||
className={classNames('notifications-dialog__footer', { | ||
'notifications-dialog__content--empty': is_empty, | ||
'notifications-dialog__content--sticky': isMobile(), | ||
})} | ||
> | ||
<Button | ||
className={classNames('dc-btn--secondary', 'notifications-dialog__clear')} | ||
disabled={is_empty} | ||
onClick={clearNotifications} | ||
> | ||
<Text size='xxs' color='prominent' weight='bold'> | ||
{localize('Clear All')} | ||
</Text> | ||
</Button> | ||
</div> | ||
</React.Fragment> | ||
); | ||
}); | ||
|
||
export default ClearAllFooter; |
Oops, something went wrong.