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';
|
import { alt } from '../alt';
|
||||||
|
|
||||||
|
|
||||||
class GlobalNotificationActions {
|
class GlobalNotificationActions {
|
||||||
constructor() {
|
constructor() {
|
||||||
this.generateActions(
|
this.generateActions(
|
||||||
'appendGlobalNotification',
|
'appendGlobalNotification',
|
||||||
|
'showNextGlobalNotification',
|
||||||
'shiftGlobalNotification',
|
'shiftGlobalNotification',
|
||||||
'emulateEmptyStore'
|
'cooldownGlobalNotifications',
|
||||||
|
'pauseGlobalNotifications',
|
||||||
|
'resumeGlobalNotifications'
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,7 +1,9 @@
|
|||||||
'use strict';
|
'use strict';
|
||||||
|
|
||||||
import React from 'react';
|
import React from 'react';
|
||||||
|
import classNames from 'classnames';
|
||||||
|
|
||||||
|
import GlobalNotificationActions from '../actions/global_notification_actions';
|
||||||
import GlobalNotificationStore from '../stores/global_notification_store';
|
import GlobalNotificationStore from '../stores/global_notification_store';
|
||||||
|
|
||||||
import Row from 'react-bootstrap/lib/Row';
|
import Row from 'react-bootstrap/lib/Row';
|
||||||
@ -9,14 +11,18 @@ import Col from 'react-bootstrap/lib/Col';
|
|||||||
|
|
||||||
import { mergeOptions } from '../utils/general_utils';
|
import { mergeOptions } from '../utils/general_utils';
|
||||||
|
|
||||||
|
const MAX_NOTIFICATION_BUBBLE_CONTAINER_WIDTH = 768;
|
||||||
|
|
||||||
let GlobalNotification = React.createClass({
|
let GlobalNotification = React.createClass({
|
||||||
|
|
||||||
getInitialState() {
|
getInitialState() {
|
||||||
|
const notificationStore = GlobalNotificationStore.getState();
|
||||||
|
|
||||||
return mergeOptions(
|
return mergeOptions(
|
||||||
{
|
{
|
||||||
containerWidth: 0
|
containerWidth: 0
|
||||||
},
|
},
|
||||||
this.extractFirstElem(GlobalNotificationStore.getState().notificationQue)
|
notificationStore
|
||||||
);
|
);
|
||||||
},
|
},
|
||||||
|
|
||||||
@ -36,35 +42,8 @@ let GlobalNotification = React.createClass({
|
|||||||
window.removeEventListener('resize', this.handleContainerResize);
|
window.removeEventListener('resize', this.handleContainerResize);
|
||||||
},
|
},
|
||||||
|
|
||||||
extractFirstElem(l) {
|
|
||||||
if(l.length > 0) {
|
|
||||||
return {
|
|
||||||
show: true,
|
|
||||||
message: l[0]
|
|
||||||
};
|
|
||||||
} else {
|
|
||||||
return {
|
|
||||||
show: false,
|
|
||||||
message: ''
|
|
||||||
};
|
|
||||||
}
|
|
||||||
},
|
|
||||||
|
|
||||||
onChange(state) {
|
onChange(state) {
|
||||||
let notification = this.extractFirstElem(state.notificationQue);
|
this.setState(state);
|
||||||
|
|
||||||
// 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
|
|
||||||
});
|
|
||||||
}
|
|
||||||
},
|
},
|
||||||
|
|
||||||
handleContainerResize() {
|
handleContainerResize() {
|
||||||
@ -73,32 +52,28 @@ let GlobalNotification = React.createClass({
|
|||||||
});
|
});
|
||||||
},
|
},
|
||||||
|
|
||||||
render() {
|
renderNotification() {
|
||||||
let notificationClass = 'ascribe-global-notification';
|
const {
|
||||||
let textClass;
|
notificationQueue: [notification],
|
||||||
|
notificationStatus,
|
||||||
|
notificationsPaused,
|
||||||
|
containerWidth } = this.state;
|
||||||
|
|
||||||
if(this.state.containerWidth > 768) {
|
if (notification && !notificationsPaused) {
|
||||||
notificationClass = 'ascribe-global-notification-bubble';
|
const notificationClasses = [];
|
||||||
|
let textClass;
|
||||||
|
|
||||||
if(this.state.show) {
|
if (this.state.containerWidth > 768) {
|
||||||
notificationClass += ' ascribe-global-notification-bubble-on';
|
notificationClasses.push('ascribe-global-notification-bubble');
|
||||||
|
notificationClasses.push(notificationStatus === 'show' ? 'ascribe-global-notification-bubble-on'
|
||||||
|
: 'ascribe-global-notification-bubble-off');
|
||||||
} else {
|
} 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 {
|
switch(notification.type) {
|
||||||
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) {
|
|
||||||
case 'success':
|
case 'success':
|
||||||
textClass = 'ascribe-global-notification-success';
|
textClass = 'ascribe-global-notification-success';
|
||||||
break;
|
break;
|
||||||
@ -106,18 +81,23 @@ let GlobalNotification = React.createClass({
|
|||||||
textClass = 'ascribe-global-notification-danger';
|
textClass = 'ascribe-global-notification-danger';
|
||||||
break;
|
break;
|
||||||
default:
|
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 (
|
return (
|
||||||
<div ref="notificationWrapper">
|
<div ref="notificationWrapper">
|
||||||
<Row>
|
<Row>
|
||||||
<Col>
|
<Col>
|
||||||
<div className={notificationClass}>
|
{this.renderNotification()}
|
||||||
<div className={textClass}>{this.state.message.message}</div>
|
|
||||||
</div>
|
|
||||||
</Col>
|
</Col>
|
||||||
</Row>
|
</Row>
|
||||||
</div>
|
</div>
|
||||||
@ -125,4 +105,4 @@ let GlobalNotification = React.createClass({
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
export default GlobalNotification;
|
export default GlobalNotification;
|
||||||
|
@ -4,36 +4,63 @@ import { alt } from '../alt';
|
|||||||
|
|
||||||
import GlobalNotificationActions from '../actions/global_notification_actions';
|
import GlobalNotificationActions from '../actions/global_notification_actions';
|
||||||
|
|
||||||
|
const GLOBAL_NOTIFICATION_COOLDOWN = 400;
|
||||||
|
|
||||||
class GlobalNotificationStore {
|
class GlobalNotificationStore {
|
||||||
constructor() {
|
constructor() {
|
||||||
this.notificationQue = [];
|
this.notificationQueue = [];
|
||||||
|
this.notificationStatus = 'ready';
|
||||||
|
this.notificationsPaused = false;
|
||||||
|
|
||||||
this.bindActions(GlobalNotificationActions);
|
this.bindActions(GlobalNotificationActions);
|
||||||
}
|
}
|
||||||
|
|
||||||
onAppendGlobalNotification(newNotification) {
|
onAppendGlobalNotification(newNotification) {
|
||||||
let notificationDelay = 0;
|
this.notificationQueue.push(newNotification);
|
||||||
for(let i = 0; i < this.notificationQue.length; i++) {
|
|
||||||
notificationDelay += this.notificationQue[i].dismissAfter;
|
|
||||||
}
|
|
||||||
|
|
||||||
this.notificationQue.push(newNotification);
|
if (!this.notificationsPaused && this.notificationStatus === 'ready') {
|
||||||
setTimeout(GlobalNotificationActions.emulateEmptyStore, notificationDelay + newNotification.dismissAfter);
|
this.showNextNotification();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onEmulateEmptyStore() {
|
showNextNotification() {
|
||||||
let actualNotificitionQue = this.notificationQue.slice();
|
this.notificationStatus = 'show';
|
||||||
|
|
||||||
this.notificationQue = [];
|
setTimeout(GlobalNotificationActions.cooldownGlobalNotifications, this.notificationQueue[0].dismissAfter);
|
||||||
|
}
|
||||||
|
|
||||||
setTimeout(() => {
|
onCooldownGlobalNotifications() {
|
||||||
this.notificationQue = actualNotificitionQue.slice();
|
// When still paused on cooldown, don't shift the queue so we can repeat the current notification.
|
||||||
GlobalNotificationActions.shiftGlobalNotification();
|
if (!this.notificationsPaused) {
|
||||||
}, 400);
|
this.notificationStatus = 'cooldown';
|
||||||
|
|
||||||
|
// Leave some time between consecutive notifications
|
||||||
|
setTimeout(GlobalNotificationActions.shiftGlobalNotification, GLOBAL_NOTIFICATION_COOLDOWN);
|
||||||
|
} else {
|
||||||
|
this.notificationStatus = 'ready';
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
onShiftGlobalNotification() {
|
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