Fix expiring polls not being displayed as such in the WebUI (#11835)

* Fix expiring polls not being displayed as such in the WebUI

* Reset expiration state and timer when a poll changes

* Refactor timer logic in `_setupTimer`, only set expiration if props have changed

* Refactor and do not use deprecated React lifecycles
This commit is contained in:
ThibG 2019-09-16 14:32:26 +02:00 committed by Eugen Rochko
parent 1882ca673d
commit 524187b653

View File

@ -32,8 +32,38 @@ class Poll extends ImmutablePureComponent {
state = { state = {
selected: {}, selected: {},
expired: null,
}; };
static getDerivedStateFromProps (props, state) {
const { poll, intl } = props;
const expired = poll.get('expired') || (new Date(poll.get('expires_at'))).getTime() < intl.now();
return (expired === state.expired) ? null : { expired };
}
componentDidMount () {
this._setupTimer();
}
componentDidUpdate () {
this._setupTimer();
}
componentWillUnmount () {
clearTimeout(this._timer);
}
_setupTimer () {
const { poll, intl } = this.props;
clearTimeout(this._timer);
if (!this.state.expired) {
const delay = (new Date(poll.get('expires_at'))).getTime() - intl.now();
this._timer = setTimeout(() => {
this.setState({ expired: true });
}, delay);
}
}
handleOptionChange = e => { handleOptionChange = e => {
const { target: { value } } = e; const { target: { value } } = e;
@ -68,12 +98,11 @@ class Poll extends ImmutablePureComponent {
this.props.dispatch(fetchPoll(this.props.poll.get('id'))); this.props.dispatch(fetchPoll(this.props.poll.get('id')));
}; };
renderOption (option, optionIndex) { renderOption (option, optionIndex, showResults) {
const { poll, disabled } = this.props; const { poll, disabled } = this.props;
const percent = poll.get('votes_count') === 0 ? 0 : (option.get('votes_count') / poll.get('votes_count')) * 100; const percent = poll.get('votes_count') === 0 ? 0 : (option.get('votes_count') / poll.get('votes_count')) * 100;
const leading = poll.get('options').filterNot(other => other.get('title') === option.get('title')).every(other => option.get('votes_count') > other.get('votes_count')); const leading = poll.get('options').filterNot(other => other.get('title') === option.get('title')).every(other => option.get('votes_count') > other.get('votes_count'));
const active = !!this.state.selected[`${optionIndex}`]; const active = !!this.state.selected[`${optionIndex}`];
const showResults = poll.get('voted') || poll.get('expired');
let titleEmojified = option.get('title_emojified'); let titleEmojified = option.get('title_emojified');
if (!titleEmojified) { if (!titleEmojified) {
@ -112,19 +141,20 @@ class Poll extends ImmutablePureComponent {
render () { render () {
const { poll, intl } = this.props; const { poll, intl } = this.props;
const { expired } = this.state;
if (!poll) { if (!poll) {
return null; return null;
} }
const timeRemaining = poll.get('expired') ? intl.formatMessage(messages.closed) : <RelativeTimestamp timestamp={poll.get('expires_at')} futureDate />; const timeRemaining = expired ? intl.formatMessage(messages.closed) : <RelativeTimestamp timestamp={poll.get('expires_at')} futureDate />;
const showResults = poll.get('voted') || poll.get('expired'); const showResults = poll.get('voted') || expired;
const disabled = this.props.disabled || Object.entries(this.state.selected).every(item => !item); const disabled = this.props.disabled || Object.entries(this.state.selected).every(item => !item);
return ( return (
<div className='poll'> <div className='poll'>
<ul> <ul>
{poll.get('options').map((option, i) => this.renderOption(option, i))} {poll.get('options').map((option, i) => this.renderOption(option, i, showResults))}
</ul> </ul>
<div className='poll__footer'> <div className='poll__footer'>