Created
June 30, 2017 22:04
-
-
Save rosskevin/6585499c7f6d97a232a80b3e3f982c92 to your computer and use it in GitHub Desktop.
material-ui NotificationCenter
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
// @flow | |
import Queue from 'es-collections/Queue' | |
import Snackbar from '@alienfast/material-ui/Snackbar' | |
import PropTypes from 'prop-types' | |
import React, {Component} from 'react' | |
import Logger from './util/Logger' | |
import Performance from './util/Performance' | |
import Button from './Button' | |
// if test, shorten duration for multiple messages - saves ~9 seconds on reset_password.feature | |
const DefaultDuration = __TEST__ ? 750 : 3000 | |
type Props = {} | |
type State = { | |
queueSize: number, | |
status: 'queueSizeChanged' | 'exited' | |
} | |
type Notification = { | |
message: string, | |
duration?: number, | |
delay?: number, | |
action?: string, | |
onAction?: Function | |
} | |
const EmptyNotification = { | |
message: '' | |
} | |
class NotificationCenter extends Component<void, Props, State> { | |
static contextTypes = { | |
eventBus: PropTypes.object.isRequired | |
} | |
props: Props | |
state: State = { | |
queueSize: 0, | |
status: 'exited' | |
} | |
subscriptions: Array<EmitterSubscription> | |
queue: Queue | |
notification: ?Notification = EmptyNotification | |
componentWillMount () { | |
log.debug('componentWillMount') | |
this.queue = new Queue() | |
const { eventBus } = this.context | |
// eventBus.registerEvent('NotificationCenter', 'notification') | |
this.subscriptions = eventBus.subscribe('notification', this.handleNotification) | |
} | |
componentWillUnmount () { | |
log.debug('componentWillUnmount') | |
const { eventBus } = this.context | |
eventBus.unsubscribe(this.subscriptions) | |
} | |
shouldComponentUpdate (nextProps: Props, nextState: State, nextContext: any) { | |
//log.debug('shouldComponentUpdate', this.queue.size) | |
// check to see if we are still showing the current notification | |
const peek = this.queue.peek() | |
//log.debug('compare notifications', this.notification === peek, this.notification, peek) | |
if (this.notification === peek) { | |
return false | |
} | |
return Performance.shouldComponentUpdate(this, nextProps, nextState, nextContext, true) | |
} | |
updateQueueSize () { | |
this.setState({ | |
queueSize: this.queue.size, | |
status: 'queueSizeChanged' | |
}) | |
} | |
handleNotification = (notification: Notification) => { | |
const { delay } = notification | |
const enqueue = () => { | |
this.queue.enqueue(notification) | |
log.debug('handleNotification', this.queue.size, notification) | |
this.updateQueueSize() | |
} | |
if (delay) { | |
setTimeout(enqueue, delay) | |
} else { | |
enqueue() | |
} | |
} | |
handleRequestClose = (event: ?SyntheticUIEvent, reason: string, onAction?: Function) => { | |
log.debug('handleRequestClose', reason, onAction, this.notification) | |
const { duration } = (this.notification ? this.notification : {}) // wacky flow maybe type | |
if (reason === 'clickaway' && !duration === 0) { // allow clickaway on duration 0 | |
log.debug(reason) | |
} else { | |
if (onAction) { | |
onAction() | |
} | |
this.queue.dequeue() | |
this.updateQueueSize() | |
} | |
} | |
handleExited = () => { | |
log.debug('handleExited', this.notification) | |
this.setState({ status: 'exited' }) | |
} | |
render () { | |
const { status } = this.state | |
const size = this.queue.size | |
let open | |
let shownNotification: ?Notification | |
if (size === 0) { | |
// We must render the snackbar with an empty notification and close it so | |
// that we still achieve the ease out effect. | |
shownNotification = this.notification | |
this.notification = EmptyNotification | |
open = false | |
} else if (status === 'queueSizeChanged' && this.notification !== EmptyNotification) { | |
// allow this message to exit | |
shownNotification = this.notification | |
open = false | |
} else { | |
// ready to display a new message from the queue | |
shownNotification = this.notification = this.queue.peek() | |
open = true | |
} | |
const { message, action: actionString, duration, onAction } = (shownNotification || {}) | |
// from the action string, create a button to trigger the action and dismiss the snackbar | |
let action | |
if (actionString) { | |
action = [ | |
<Button | |
key={actionString} | |
color='accent' | |
dense | |
onClick={() => onAction ? onAction() : null} | |
> | |
{actionString} | |
</Button> | |
] | |
} | |
const snackbarProps = { | |
open, | |
autoHideDuration: (duration === undefined ? DefaultDuration : duration) | |
} | |
log.debug('render Queue size:', size, ' status: ', status, message, snackbarProps) | |
return ( | |
<Snackbar | |
key={message} | |
{...snackbarProps} | |
action={action} | |
onRequestClose={this.handleRequestClose} | |
onExited={this.handleExited} | |
SnackbarContentProps={{ | |
'aria-describedby': 'message-id' | |
}} | |
message={<span id='message-id'>{message}</span>} | |
/> | |
) | |
} | |
} | |
const log = Logger.get('NotificationCenter') | |
log.debug('DefaultDuration', DefaultDuration, __TEST__) | |
export default NotificationCenter |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment