mirror of
https://github.com/ascribe/onion.git
synced 2024-12-22 17:33:14 +01:00
Implement pause and resume functionality to global notifications
Also part of this change: * Handle the notification cooldown periods using status changes rather than emptying the queue * Refactor how notifications are rendered
This commit is contained in:
parent
60bf4b12f5
commit
6649b7d7f1
@ -2,13 +2,15 @@
|
||||
|
||||
import { alt } from '../alt';
|
||||
|
||||
|
||||
class GlobalNotificationActions {
|
||||
constructor() {
|
||||
this.generateActions(
|
||||
'appendGlobalNotification',
|
||||
'showNextGlobalNotification',
|
||||
'shiftGlobalNotification',
|
||||
'emulateEmptyStore'
|
||||
'cooldownGlobalNotifications',
|
||||
'pauseGlobalNotifications',
|
||||
'resumeGlobalNotifications'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -1,7 +1,9 @@
|
||||
'use strict';
|
||||
|
||||
import React from 'react';
|
||||
import classNames from 'classnames';
|
||||
|
||||
import GlobalNotificationActions from '../actions/global_notification_actions';
|
||||
import GlobalNotificationStore from '../stores/global_notification_store';
|
||||
|
||||
import Row from 'react-bootstrap/lib/Row';
|
||||
@ -9,14 +11,18 @@ import Col from 'react-bootstrap/lib/Col';
|
||||
|
||||
import { mergeOptions } from '../utils/general_utils';
|
||||
|
||||
const MAX_NOTIFICATION_BUBBLE_CONTAINER_WIDTH = 768;
|
||||
|
||||
let GlobalNotification = React.createClass({
|
||||
|
||||
getInitialState() {
|
||||
const notificationStore = GlobalNotificationStore.getState();
|
||||
|
||||
return mergeOptions(
|
||||
{
|
||||
containerWidth: 0
|
||||
},
|
||||
this.extractFirstElem(GlobalNotificationStore.getState().notificationQue)
|
||||
notificationStore
|
||||
);
|
||||
},
|
||||
|
||||
@ -36,35 +42,8 @@ let GlobalNotification = React.createClass({
|
||||
window.removeEventListener('resize', this.handleContainerResize);
|
||||
},
|
||||
|
||||
extractFirstElem(l) {
|
||||
if(l.length > 0) {
|
||||
return {
|
||||
show: true,
|
||||
message: l[0]
|
||||
};
|
||||
} else {
|
||||
return {
|
||||
show: false,
|
||||
message: ''
|
||||
};
|
||||
}
|
||||
},
|
||||
|
||||
onChange(state) {
|
||||
let notification = this.extractFirstElem(state.notificationQue);
|
||||
|
||||
// error handling for notifications
|
||||
if(notification.message && notification.type === 'danger') {
|
||||
console.logGlobal(new Error(notification.message.message));
|
||||
}
|
||||
|
||||
if(notification.show) {
|
||||
this.setState(notification);
|
||||
} else {
|
||||
this.setState({
|
||||
show: false
|
||||
});
|
||||
}
|
||||
this.setState(state);
|
||||
},
|
||||
|
||||
handleContainerResize() {
|
||||
@ -73,32 +52,28 @@ let GlobalNotification = React.createClass({
|
||||
});
|
||||
},
|
||||
|
||||
render() {
|
||||
let notificationClass = 'ascribe-global-notification';
|
||||
renderNotification() {
|
||||
const {
|
||||
notificationQueue: [notification],
|
||||
notificationStatus,
|
||||
notificationsPaused,
|
||||
containerWidth } = this.state;
|
||||
|
||||
if (notification && !notificationsPaused) {
|
||||
const notificationClasses = [];
|
||||
let textClass;
|
||||
|
||||
if(this.state.containerWidth > 768) {
|
||||
notificationClass = 'ascribe-global-notification-bubble';
|
||||
|
||||
if(this.state.show) {
|
||||
notificationClass += ' ascribe-global-notification-bubble-on';
|
||||
if (this.state.containerWidth > 768) {
|
||||
notificationClasses.push('ascribe-global-notification-bubble');
|
||||
notificationClasses.push(notificationStatus === 'show' ? 'ascribe-global-notification-bubble-on'
|
||||
: 'ascribe-global-notification-bubble-off');
|
||||
} else {
|
||||
notificationClass += ' ascribe-global-notification-bubble-off';
|
||||
notificationClasses.push('ascribe-global-notification');
|
||||
notificationClasses.push(notificationStatus === 'show' ? 'ascribe-global-notification-on'
|
||||
: 'ascribe-global-notification-off');
|
||||
}
|
||||
|
||||
} else {
|
||||
notificationClass = 'ascribe-global-notification';
|
||||
|
||||
if(this.state.show) {
|
||||
notificationClass += ' ascribe-global-notification-on';
|
||||
} else {
|
||||
notificationClass += ' ascribe-global-notification-off';
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
if(this.state.message) {
|
||||
switch(this.state.message.type) {
|
||||
switch(notification.type) {
|
||||
case 'success':
|
||||
textClass = 'ascribe-global-notification-success';
|
||||
break;
|
||||
@ -106,18 +81,23 @@ let GlobalNotification = React.createClass({
|
||||
textClass = 'ascribe-global-notification-danger';
|
||||
break;
|
||||
default:
|
||||
console.warn('Could not find a matching type in global_notification.js');
|
||||
}
|
||||
console.warn('Could not find a matching notification type in global_notification.js');
|
||||
}
|
||||
|
||||
return (
|
||||
<div className={classNames(...notificationClasses)}>
|
||||
<div className={textClass}>{notification.message}</div>
|
||||
</div>
|
||||
);
|
||||
}
|
||||
},
|
||||
|
||||
render() {
|
||||
return (
|
||||
<div ref="notificationWrapper">
|
||||
<Row>
|
||||
<Col>
|
||||
<div className={notificationClass}>
|
||||
<div className={textClass}>{this.state.message.message}</div>
|
||||
</div>
|
||||
{this.renderNotification()}
|
||||
</Col>
|
||||
</Row>
|
||||
</div>
|
||||
|
@ -4,36 +4,63 @@ import { alt } from '../alt';
|
||||
|
||||
import GlobalNotificationActions from '../actions/global_notification_actions';
|
||||
|
||||
const GLOBAL_NOTIFICATION_COOLDOWN = 400;
|
||||
|
||||
class GlobalNotificationStore {
|
||||
constructor() {
|
||||
this.notificationQue = [];
|
||||
this.notificationQueue = [];
|
||||
this.notificationStatus = 'ready';
|
||||
this.notificationsPaused = false;
|
||||
|
||||
this.bindActions(GlobalNotificationActions);
|
||||
}
|
||||
|
||||
onAppendGlobalNotification(newNotification) {
|
||||
let notificationDelay = 0;
|
||||
for(let i = 0; i < this.notificationQue.length; i++) {
|
||||
notificationDelay += this.notificationQue[i].dismissAfter;
|
||||
this.notificationQueue.push(newNotification);
|
||||
|
||||
if (!this.notificationsPaused && this.notificationStatus === 'ready') {
|
||||
this.showNextNotification();
|
||||
}
|
||||
}
|
||||
|
||||
this.notificationQue.push(newNotification);
|
||||
setTimeout(GlobalNotificationActions.emulateEmptyStore, notificationDelay + newNotification.dismissAfter);
|
||||
showNextNotification() {
|
||||
this.notificationStatus = 'show';
|
||||
|
||||
setTimeout(GlobalNotificationActions.cooldownGlobalNotifications, this.notificationQueue[0].dismissAfter);
|
||||
}
|
||||
|
||||
onEmulateEmptyStore() {
|
||||
let actualNotificitionQue = this.notificationQue.slice();
|
||||
onCooldownGlobalNotifications() {
|
||||
// When still paused on cooldown, don't shift the queue so we can repeat the current notification.
|
||||
if (!this.notificationsPaused) {
|
||||
this.notificationStatus = 'cooldown';
|
||||
|
||||
this.notificationQue = [];
|
||||
|
||||
setTimeout(() => {
|
||||
this.notificationQue = actualNotificitionQue.slice();
|
||||
GlobalNotificationActions.shiftGlobalNotification();
|
||||
}, 400);
|
||||
// Leave some time between consecutive notifications
|
||||
setTimeout(GlobalNotificationActions.shiftGlobalNotification, GLOBAL_NOTIFICATION_COOLDOWN);
|
||||
} else {
|
||||
this.notificationStatus = 'ready';
|
||||
}
|
||||
}
|
||||
|
||||
onShiftGlobalNotification() {
|
||||
this.notificationQue.shift();
|
||||
this.notificationQueue.shift();
|
||||
|
||||
if (!this.notificationsPaused && this.notificationQueue.length > 0) {
|
||||
this.showNextNotification();
|
||||
} else {
|
||||
this.notificationStatus = 'ready';
|
||||
}
|
||||
}
|
||||
|
||||
onPauseGlobalNotifications() {
|
||||
this.notificationsPaused = true;
|
||||
}
|
||||
|
||||
onResumeGlobalNotifications() {
|
||||
this.notificationsPaused = false;
|
||||
|
||||
if (this.notificationStatus === 'ready' && this.notificationQueue.length > 0) {
|
||||
this.showNextNotification();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user