Show user what options they have voted (#11195)

* Add own_votes field to poll results in REST API

Fixes #10679

* Display user votes in WebUI

* Update styling

* Add vote checkmark to public pages
This commit is contained in:
ThibG 2019-09-22 14:15:18 +02:00 committed by Eugen Rochko
parent 26b810561a
commit b359974d9b
6 changed files with 31 additions and 6 deletions

View File

@ -73,8 +73,9 @@ export function normalizePoll(poll) {
const emojiMap = makeEmojiMap(normalPoll); const emojiMap = makeEmojiMap(normalPoll);
normalPoll.options = poll.options.map(option => ({ normalPoll.options = poll.options.map((option, index) => ({
...option, ...option,
voted: poll.own_votes && poll.own_votes.includes(index),
title_emojified: emojify(escapeTextContentForBrowser(option.title), emojiMap), title_emojified: emojify(escapeTextContentForBrowser(option.title), emojiMap),
})); }));

View File

@ -10,6 +10,7 @@ import spring from 'react-motion/lib/spring';
import escapeTextContentForBrowser from 'escape-html'; import escapeTextContentForBrowser from 'escape-html';
import emojify from 'mastodon/features/emoji/emoji'; import emojify from 'mastodon/features/emoji/emoji';
import RelativeTimestamp from './relative_timestamp'; import RelativeTimestamp from './relative_timestamp';
import Icon from 'mastodon/components/icon';
const messages = defineMessages({ const messages = defineMessages({
closed: { id: 'poll.closed', defaultMessage: 'Closed' }, closed: { id: 'poll.closed', defaultMessage: 'Closed' },
@ -103,6 +104,7 @@ class Poll extends ImmutablePureComponent {
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 voted = option.get('voted') || (poll.get('own_votes') && poll.get('own_votes').includes(optionIndex));
let titleEmojified = option.get('title_emojified'); let titleEmojified = option.get('title_emojified');
if (!titleEmojified) { if (!titleEmojified) {
@ -131,7 +133,10 @@ class Poll extends ImmutablePureComponent {
/> />
{!showResults && <span className={classNames('poll__input', { checkbox: poll.get('multiple'), active })} />} {!showResults && <span className={classNames('poll__input', { checkbox: poll.get('multiple'), active })} />}
{showResults && <span className='poll__number'>{Math.round(percent)}%</span>} {showResults && <span className='poll__number'>
{!!voted && <Icon id='check' className='poll__vote__mark' />}
{Math.round(percent)}%
</span>}
<span dangerouslySetInnerHTML={{ __html: titleEmojified }} /> <span dangerouslySetInnerHTML={{ __html: titleEmojified }} />
</label> </label>

View File

@ -95,13 +95,19 @@
&__number { &__number {
display: inline-block; display: inline-block;
width: 36px; width: 48px;
font-weight: 700; font-weight: 700;
padding: 0 10px; padding: 0 10px;
text-align: right; text-align: right;
margin-top: auto; margin-top: auto;
margin-bottom: auto; margin-bottom: auto;
flex: 0 0 36px; flex: 0 0 48px;
}
&__vote__mark {
float: left;
color: $valid-value-color;
line-height: 18px;
} }
&__footer { &__footer {

View File

@ -54,6 +54,10 @@ class Poll < ApplicationRecord
account.id == account_id || votes.where(account: account).exists? account.id == account_id || votes.where(account: account).exists?
end end
def own_votes(account)
votes.where(account: account).pluck(:choice)
end
delegate :local?, to: :account delegate :local?, to: :account
def remote? def remote?

View File

@ -8,6 +8,7 @@ class REST::PollSerializer < ActiveModel::Serializer
has_many :emojis, serializer: REST::CustomEmojiSerializer has_many :emojis, serializer: REST::CustomEmojiSerializer
attribute :voted, if: :current_user? attribute :voted, if: :current_user?
attribute :own_votes, if: :current_user?
def id def id
object.id.to_s object.id.to_s
@ -21,6 +22,10 @@ class REST::PollSerializer < ActiveModel::Serializer
object.voted?(current_user.account) object.voted?(current_user.account)
end end
def own_votes
object.own_votes(current_user.account)
end
def current_user? def current_user?
!current_user.nil? !current_user.nil?
end end

View File

@ -1,15 +1,19 @@
- show_results = (user_signed_in? && poll.voted?(current_account)) || poll.expired? - show_results = (user_signed_in? && poll.voted?(current_account)) || poll.expired?
- own_votes = user_signed_in? ? poll.own_votes(current_account) : []
.poll .poll
%ul %ul
- poll.loaded_options.each do |option| - poll.loaded_options.each_with_index do |option, index|
%li %li
- if show_results - if show_results
- percent = poll.votes_count > 0 ? 100 * option.votes_count / poll.votes_count : 0 - percent = poll.votes_count > 0 ? 100 * option.votes_count / poll.votes_count : 0
%span.poll__chart{ style: "width: #{percent}%" } %span.poll__chart{ style: "width: #{percent}%" }
%label.poll__text>< %label.poll__text><
%span.poll__number= percent.round %span.poll__number><
- if own_votes.include?(index)
%i.poll__vote__mark.fa.fa-check
= percent.round
= Formatter.instance.format_poll_option(status, option, autoplay: autoplay) = Formatter.instance.format_poll_option(status, option, autoplay: autoplay)
- else - else
%label.poll__text>< %label.poll__text><