Dismiss notifications from component
This commit is contained in:
parent
67d9177a91
commit
fcb47a2cc5
@ -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 },
|
||||
|
||||
@ -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<string, Notification>
|
||||
messages: Message[]
|
||||
@ -63,6 +64,7 @@ export default class App extends React.PureComponent<AppProps, AppState> {
|
||||
active,
|
||||
alerts,
|
||||
dismissAlert,
|
||||
dismissNotification,
|
||||
notifications,
|
||||
messages,
|
||||
messagesCount,
|
||||
@ -86,7 +88,10 @@ export default class App extends React.PureComponent<AppProps, AppState> {
|
||||
stream={streams[constants.ME]}
|
||||
/>
|
||||
<Alerts alerts={alerts} dismiss={dismissAlert} />
|
||||
<Notifications notifications={notifications} />
|
||||
<Notifications
|
||||
dismiss={dismissNotification}
|
||||
notifications={notifications}
|
||||
/>
|
||||
<Media />
|
||||
<Chat
|
||||
messages={messages}
|
||||
|
||||
45
src/client/components/Notifications.test.tsx
Normal file
45
src/client/components/Notifications.test.tsx
Normal file
@ -0,0 +1,45 @@
|
||||
import Notifications from './Notifications'
|
||||
import React from 'react'
|
||||
import ReactDOM from 'react-dom'
|
||||
import { Notification, NotificationDismissAction } from '../actions/NotifyActions'
|
||||
|
||||
describe('Notifications', () => {
|
||||
|
||||
let notifications: Record<string, Notification>
|
||||
let dismiss: jest.Mock<NotificationDismissAction, [string]>
|
||||
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<Notifications>(resolve => {
|
||||
ReactDOM.render(
|
||||
<Notifications
|
||||
ref={n => 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' ]])
|
||||
})
|
||||
})
|
||||
|
||||
})
|
||||
@ -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<string, Notification>
|
||||
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 (
|
||||
<div className={classnames(notification.type, 'notification')}>
|
||||
{notification.message}
|
||||
</div>
|
||||
)
|
||||
},
|
||||
)
|
||||
|
||||
export default class Notifications
|
||||
extends React.PureComponent<NotificationProps> {
|
||||
extends React.PureComponent<NotificationsProps> {
|
||||
static defaultProps = {
|
||||
max: 10,
|
||||
}
|
||||
render () {
|
||||
const { notifications, max } = this.props
|
||||
const { dismiss, notifications, max } = this.props
|
||||
return (
|
||||
<div className="notifications">
|
||||
<TransitionGroup>
|
||||
@ -30,11 +55,11 @@ extends React.PureComponent<NotificationProps> {
|
||||
classNames='fade'
|
||||
timeout={transitionTimeout}
|
||||
>
|
||||
<div
|
||||
className={classnames(notifications[id].type, 'notification')}
|
||||
>
|
||||
{notifications[id].message}
|
||||
</div>
|
||||
<Notification
|
||||
notification={notifications[id]}
|
||||
dismiss={dismiss}
|
||||
timeout={10000}
|
||||
/>
|
||||
</CSSTransition>
|
||||
))}
|
||||
</TransitionGroup>
|
||||
|
||||
@ -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,
|
||||
|
||||
@ -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]()
|
||||
})
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user