Skip to content

Commit e7b1f39

Browse files
ClearlyClairehiyuki2578
authored andcommitted
Fix expiring polls not being displayed as such in the WebUI (mastodon#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
1 parent c740187 commit e7b1f39

1 file changed

Lines changed: 35 additions & 5 deletions

File tree

  • app/javascript/mastodon/components

app/javascript/mastodon/components/poll.js

Lines changed: 35 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -32,8 +32,38 @@ class Poll extends ImmutablePureComponent {
3232

3333
state = {
3434
selected: {},
35+
expired: null,
3536
};
3637

38+
static getDerivedStateFromProps (props, state) {
39+
const { poll, intl } = props;
40+
const expired = poll.get('expired') || (new Date(poll.get('expires_at'))).getTime() < intl.now();
41+
return (expired === state.expired) ? null : { expired };
42+
}
43+
44+
componentDidMount () {
45+
this._setupTimer();
46+
}
47+
48+
componentDidUpdate () {
49+
this._setupTimer();
50+
}
51+
52+
componentWillUnmount () {
53+
clearTimeout(this._timer);
54+
}
55+
56+
_setupTimer () {
57+
const { poll, intl } = this.props;
58+
clearTimeout(this._timer);
59+
if (!this.state.expired) {
60+
const delay = (new Date(poll.get('expires_at'))).getTime() - intl.now();
61+
this._timer = setTimeout(() => {
62+
this.setState({ expired: true });
63+
}, delay);
64+
}
65+
}
66+
3767
handleOptionChange = e => {
3868
const { target: { value } } = e;
3969

@@ -68,12 +98,11 @@ class Poll extends ImmutablePureComponent {
6898
this.props.dispatch(fetchPoll(this.props.poll.get('id')));
6999
};
70100

71-
renderOption (option, optionIndex) {
101+
renderOption (option, optionIndex, showResults) {
72102
const { poll, disabled } = this.props;
73103
const percent = poll.get('votes_count') === 0 ? 0 : (option.get('votes_count') / poll.get('votes_count')) * 100;
74104
const leading = poll.get('options').filterNot(other => other.get('title') === option.get('title')).every(other => option.get('votes_count') > other.get('votes_count'));
75105
const active = !!this.state.selected[`${optionIndex}`];
76-
const showResults = poll.get('voted') || poll.get('expired');
77106

78107
let titleEmojified = option.get('title_emojified');
79108
if (!titleEmojified) {
@@ -112,19 +141,20 @@ class Poll extends ImmutablePureComponent {
112141

113142
render () {
114143
const { poll, intl } = this.props;
144+
const { expired } = this.state;
115145

116146
if (!poll) {
117147
return null;
118148
}
119149

120-
const timeRemaining = poll.get('expired') ? intl.formatMessage(messages.closed) : <RelativeTimestamp timestamp={poll.get('expires_at')} futureDate />;
121-
const showResults = poll.get('voted') || poll.get('expired');
150+
const timeRemaining = expired ? intl.formatMessage(messages.closed) : <RelativeTimestamp timestamp={poll.get('expires_at')} futureDate />;
151+
const showResults = poll.get('voted') || expired;
122152
const disabled = this.props.disabled || Object.entries(this.state.selected).every(item => !item);
123153

124154
return (
125155
<div className='poll'>
126156
<ul>
127-
{poll.get('options').map((option, i) => this.renderOption(option, i))}
157+
{poll.get('options').map((option, i) => this.renderOption(option, i, showResults))}
128158
</ul>
129159

130160
<div className='poll__footer'>

0 commit comments

Comments
 (0)