From fcb47a2cc58ed733f62a09ad1950d4586f4c2eb2 Mon Sep 17 00:00:00 2001 From: Jerko Steiner Date: Sun, 17 Nov 2019 14:10:33 -0300 Subject: [PATCH] Dismiss notifications from component --- src/client/actions/NotifyActions.ts | 8 +--- src/client/components/App.tsx | 9 +++- src/client/components/Notifications.test.tsx | 45 ++++++++++++++++++++ src/client/components/Notifications.tsx | 43 +++++++++++++++---- src/client/containers/App.tsx | 3 +- src/client/reducers/alerts.test.ts | 5 --- 6 files changed, 89 insertions(+), 24 deletions(-) create mode 100644 src/client/components/Notifications.test.tsx diff --git a/src/client/actions/NotifyActions.ts b/src/client/actions/NotifyActions.ts index 3b10653..e34b520 100644 --- a/src/client/actions/NotifyActions.ts +++ b/src/client/actions/NotifyActions.ts @@ -3,8 +3,6 @@ import { Dispatch } from 'redux' import * as constants from '../constants' import { ThunkResult } from '../store' -const TIMEOUT = 5000 - function format (string: string, args: string[]) { string = args .reduce((string, arg, i) => string.replace('{' + i + '}', arg), string) @@ -19,10 +17,6 @@ function notify(dispatch: Dispatch, type: NotifyType, args: string[]) { const id = uniqueId('notification') const payload: Notification = { id, type, message } - setTimeout(() => { - dispatch(dismissNotification(id)) - }, TIMEOUT) - return addNotification(payload) } @@ -45,7 +39,7 @@ function addNotification(payload: Notification): NotificationAddAction { } } -function dismissNotification(id: string): NotificationDismissAction { +export function dismissNotification(id: string): NotificationDismissAction { return { type: constants.NOTIFY_DISMISS, payload: { id }, diff --git a/src/client/components/App.tsx b/src/client/components/App.tsx index 2d735b4..d692742 100644 --- a/src/client/components/App.tsx +++ b/src/client/components/App.tsx @@ -2,7 +2,7 @@ import map from 'lodash/map' import React from 'react' import Peer from 'simple-peer' import { Message } from '../actions/ChatActions' -import { Alert, Notification } from '../actions/NotifyActions' +import { Alert, Notification, dismissNotification } from '../actions/NotifyActions' import { TextMessage } from '../actions/PeerActions' import { AddStreamPayload } from '../actions/StreamActions' import * as constants from '../constants' @@ -17,6 +17,7 @@ export interface AppProps { active: string | null alerts: Alert[] dismissAlert: (alert: Alert) => void + dismissNotification: typeof dismissNotification init: () => void notifications: Record messages: Message[] @@ -63,6 +64,7 @@ export default class App extends React.PureComponent { active, alerts, dismissAlert, + dismissNotification, notifications, messages, messagesCount, @@ -86,7 +88,10 @@ export default class App extends React.PureComponent { stream={streams[constants.ME]} /> - + { + + let notifications: Record + let dismiss: jest.Mock + beforeEach(() => { + notifications = { + one: { + id: 'one', + message: 'test', + type: 'error', + }, + } + dismiss = jest.fn() + }) + + let div: HTMLDivElement + async function render() { + div = document.createElement('div') + return new Promise(resolve => { + ReactDOM.render( + resolve(n!)} + notifications={notifications} + dismiss={dismiss} + />, + div, + ) + }) + } + + describe('render', () => { + it('renders and sets a timeout for notification', async () => { + await render() + expect(dismiss.mock.calls).toEqual([]) + ReactDOM.unmountComponentAtNode(div) + expect(dismiss.mock.calls).toEqual([[ 'one' ]]) + }) + }) + +}) diff --git a/src/client/components/Notifications.tsx b/src/client/components/Notifications.tsx index a679048..bebffd2 100644 --- a/src/client/components/Notifications.tsx +++ b/src/client/components/Notifications.tsx @@ -2,10 +2,11 @@ import CSSTransition from 'react-transition-group/CSSTransition' import TransitionGroup from 'react-transition-group/TransitionGroup' import React from 'react' import classnames from 'classnames' -import { Notification } from '../actions/NotifyActions' +import { dismissNotification, Notification } from '../actions/NotifyActions' -export interface NotificationProps { +export interface NotificationsProps { notifications: Record + dismiss: typeof dismissNotification max: number } @@ -14,13 +15,37 @@ const transitionTimeout = { exit: 100, } +export interface NotificationProps { + notification: Notification + dismiss: typeof dismissNotification + timeout: number +} + +const Notification = React.memo( + function Notification(props: NotificationProps) { + const { dismiss, notification } = props + React.useEffect(() => { + const timeout = setTimeout(dismiss, props.timeout, notification.id) + return () => { + clearTimeout(timeout) + dismiss(notification.id) + } + }, []) + return ( +
+ {notification.message} +
+ ) + }, +) + export default class Notifications -extends React.PureComponent { +extends React.PureComponent { static defaultProps = { max: 10, } render () { - const { notifications, max } = this.props + const { dismiss, notifications, max } = this.props return (
@@ -30,11 +55,11 @@ extends React.PureComponent { classNames='fade' timeout={transitionTimeout} > -
- {notifications[id].message} -
+ ))}
diff --git a/src/client/containers/App.tsx b/src/client/containers/App.tsx index 33668a1..3984fc2 100644 --- a/src/client/containers/App.tsx +++ b/src/client/containers/App.tsx @@ -1,7 +1,7 @@ import { connect } from 'react-redux' import { init } from '../actions/CallActions' import { play } from '../actions/MediaActions' -import { dismissAlert } from '../actions/NotifyActions' +import { dismissAlert, dismissNotification } from '../actions/NotifyActions' import { sendFile, sendMessage } from '../actions/PeerActions' import { toggleActive } from '../actions/StreamActions' import App from '../components/App' @@ -23,6 +23,7 @@ const mapDispatchToProps = { toggleActive, sendMessage, dismissAlert: dismissAlert, + dismissNotification, init, onSendFile: sendFile, play, diff --git a/src/client/reducers/alerts.test.ts b/src/client/reducers/alerts.test.ts index 5d69830..321e635 100644 --- a/src/client/reducers/alerts.test.ts +++ b/src/client/reducers/alerts.test.ts @@ -83,11 +83,6 @@ describe('reducers/alerts', () => { }]) }) - it('dismisses notification after a timeout', () => { - jest.runAllTimers() - expect(store.getState().notifications).toEqual({}) - }) - it('does not fail when no arguments', () => { notifyActions[type]() })