feature (notification): proper notification system

This commit is contained in:
Mickael KERJEAN
2018-04-06 13:09:22 +10:00
parent 22d2cd7b00
commit 4b06b8a802
14 changed files with 185 additions and 145 deletions

View File

@ -1,68 +1,107 @@
import React from 'react';
import PropTypes from 'prop-types';
import ReactCSSTransitionGroup from 'react-addons-css-transition-group';
import { NgIf } from './';
import { notify } from '../helpers/';
import './notification.scss';
export class Notification extends React.Component {
constructor(props){
super(props);
this.state = {
visible: null,
error: null,
timeout: null
appear: false,
message_text: null,
message_type: null
};
}
componentWillMount(){
this.componentWillReceiveProps(this.props);
}
function TaskManager(){
let jobs = [];
let is_running = false;
componentWillUnmount(){
window.clearTimeout(this.timeout);
}
componentWillReceiveProps(props){
if(props.error !== null){
this.componentWillUnmount();
this.setState({visible: true, error: props.error});
this.timeout = window.setTimeout(() => {
this.setState({visible: null});
}, 5000);
const ret = {
addJob: (job) => {
jobs.push(job);
if(is_running === false){
is_running = true;
ret._executor();
}
},
_executor: () => {
let job = jobs.shift();
if(!job){
is_running = false;
return Promise.resolve();
}
return job().then(ret._executor);
}
};
return ret;
}
this.runner = new TaskManager();
}
toggleVisibility(){
this.setState({visible: !this.state.visible});
}
formatError(err){
if(typeof err === 'object'){
if(err && err.message){
return err.message;
}else{
return JSON.stringify(err);
componentDidMount(){
notify.subscribe((_message, type) => {
let job = playMessage.bind(this, {
text: stringify(_message),
type: type
});
this.runner.addJob(job);
});
function stringify(data){
if(typeof data === 'object' && data.message){
return data.message;
}else if(typeof data === 'string'){
return data;
}
}else if(typeof err === 'string'){
return err;
}else{
throw('unrecognized notification');
return JSON.stringify(data);
}
function playMessage(message){
const displayMessage = (message) => {
this.setState({
appear: true,
message_text: message.text,
message_type: message.type
});
return Promise.resolve(message);
};
const waitForABit = (timeout, message) => {
return new Promise((done, err) => {
window.setTimeout(() => {
done(message);
}, timeout);
});
};
const hideMessage = (message) => {
this.setState({
appear: false
});
return Promise.resolve(message);
};
return displayMessage(message)
.then(waitForABit.bind(this, 5000))
.then(hideMessage)
.then(waitForABit.bind(this, 1000));
}
}
close(){
this.setState({ appear: false });
}
render(){
return (
<NgIf cond={this.state.visible === true}>
<div className="component_notification">
<div onClick={this.toggleVisibility.bind(this)}>
{this.formatError(this.state.error)}
<NgIf cond={this.state.appear === true} className="component_notification no-select">
<ReactCSSTransitionGroup transitionName="notification" transitionLeave={true} transitionLeaveTimeout={200} transitionEnter={true} transitionEnterTimeout={500}>
<div className={"component_notification--container "+(this.state.message_type || 'info')}>
<div className="message">
{ this.state.message_text }
</div>
<div className="close" onClick={this.close.bind(this)}>X</div>
</div>
</div>
</ReactCSSTransitionGroup>
</NgIf>
);
}
}
Notification.propTypes = {
error: PropTypes.any
}