import React from "react"; import ReactCSSTransitionGroup from "react-addons-css-transition-group"; import { NgIf, Icon } from "./"; import { notify } from "../helpers/"; import { t } from "../locales/"; import "./notification.scss"; export class Notification extends React.Component { constructor(props) { super(props); this.state = { appear: false, message_text: null, message_type: null, }; this.runner = new TaskManager(); this.notification_current = null; } componentDidMount() { this.runner.before_run((task) => { this.notification_current = task; }); notify.subscribe((message, type) => { this.runner.addTask(Task( this.openNotification.bind(this, { text: stringify(message), type: type }), this.closeNotification.bind(this), 8000, 500, )); }); function stringify(data) { if (typeof data === "object" && data.message) { return data.message; } else if (typeof data === "string") { return data; } return JSON.stringify(data); } } closeNotification() { return new Promise((done) => { this.setState({ appear: false, }, done); }); } openNotification(message) { return new Promise((done) => { this.setState({ appear: true, message_text: message.text, message_type: message.type, }, done); }); } cancelAnimation() { return this.notification_current.cancel(); } render() { return (
{ t(this.state.message_text || "") }
); } } function TaskManager() { const tasks = []; let is_running = false; let subscriber = null; let current_task = null; const ret ={ addTask: function(task) { current_task && current_task.cancel(); tasks.push(task); if (tasks.length > 20) { tasks.splice(0, tasks.length - 10); } if (is_running === false) { is_running = true; ret._run(); } }, before_run: function(fn) { subscriber = fn; }, _run: function() { current_task = tasks.shift(); if (!current_task) { is_running = false; return Promise.resolve(); } else { const mode = tasks.length > 0 ? "minimal" : "normal"; subscriber(current_task, mode); return current_task.run(mode).then(ret._run); } }, }; return ret; } function Task(_runCallback, _finishCallback, wait_time_before_finish, minimum_running_time) { let start_date = null; let done = null; const promise = new Promise((_done) => { done = _done; }); let timeout = null; const ret = { run: function(mode = "normal") { const wait = mode === "minimal" ? minimum_running_time : wait_time_before_finish; start_date = new Date(); new Promise((_done) => { timeout = window.setTimeout(() => { _done(); }, 200); }) .then(_runCallback) .then(() => new Promise((_done) => { timeout = window.setTimeout(() => { _done(); }, wait); })) .then(() => { ret._complete(); }); return promise; }, cancel: function() { window.clearTimeout(timeout); timeout = null; const elapsed_time = new Date() - start_date; if (elapsed_time < minimum_running_time) { window.setTimeout(() => { ret._complete(); }, minimum_running_time - elapsed_time); } else { ret._complete(); } return promise; }, _complete: function() { if (done) { _finishCallback(); done(); } done = null; return Promise.resolve(); }, }; return ret; }