pagraphcontrol/components/log/index.js
2020-06-18 16:23:41 +03:00

92 lines
1.9 KiB
JavaScript

const {
compose,
map,
filter,
differenceWith,
takeLast,
} = require('ramda');
const React = require('react');
const { TransitionGroup, CSSTransition } = require('react-transition-group');
const r = require('r-dom');
const { connect } = require('react-redux');
const weakmapId = require('../../utils/weakmap-id');
const { pulse: pulseActions } = require('../../actions');
const { primaryPulseServer } = require('../../reducers/pulse');
const actionTypeText = {
[pulseActions.ready]: 'Connected to PulseAudio',
[pulseActions.close]: 'Disconnected from PulseAudio',
};
class Log extends React.Component {
constructor(props) {
super(props);
this.state = {
removedItems: [],
};
}
removeItem(item) {
this.setState({
removedItems: takeLast(10, this.state.removedItems.concat(weakmapId(item))),
});
}
shouldShowItem(item) {
return !this.state.removedItems.includes(weakmapId(item));
}
itemText(item) {
if (item.type === 'error') {
return `${item.error.name}: ${item.error.message}`;
}
return actionTypeText[item.action] || item.action;
}
componentDidUpdate(previousProps) {
const newItems = differenceWith((a, b) => a === b, this.props.log.items, previousProps.log.items);
newItems.forEach(item => setTimeout(() => {
this.removeItem(item);
}, this.props.itemLifetime));
}
render() {
return r.div({
className: 'log',
}, r(TransitionGroup, compose(
map(item => r(CSSTransition, {
key: weakmapId(item),
className: 'log-item-transition',
timeout: { enter: 300, leave: 2000 },
}, r.div({
classSet: {
'log-item': true,
'log-item-error': item.type === 'error',
'log-item-info': item.type === 'info',
},
}, this.itemText(item)))),
filter(item => this.shouldShowItem(item)),
)(this.props.log.items)));
}
}
Log.defaultProps = {
itemLifetime: 5000,
};
module.exports = connect(
state => ({
log: state.pulse[primaryPulseServer].log,
}),
)(Log);