|
|
@ -40,32 +40,13 @@ const PollPercentageBar: React.FC<IPollPercentageBar> = ({ percent, leading }):
|
|
|
|
);
|
|
|
|
);
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
interface IPollOption {
|
|
|
|
interface IPollOptionText extends IPollOption {
|
|
|
|
poll: PollEntity,
|
|
|
|
percent: number,
|
|
|
|
option: PollOptionEntity,
|
|
|
|
|
|
|
|
index: number,
|
|
|
|
|
|
|
|
showResults?: boolean,
|
|
|
|
|
|
|
|
disabled?: boolean,
|
|
|
|
|
|
|
|
active: boolean,
|
|
|
|
|
|
|
|
onToggle: (value: number) => void,
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
const PollOption: React.FC<IPollOption> = ({
|
|
|
|
const PollOptionText: React.FC<IPollOptionText> = ({ poll, option, index, active, disabled, percent, showResults, onToggle }) => {
|
|
|
|
poll,
|
|
|
|
|
|
|
|
option,
|
|
|
|
|
|
|
|
index,
|
|
|
|
|
|
|
|
showResults,
|
|
|
|
|
|
|
|
disabled,
|
|
|
|
|
|
|
|
active,
|
|
|
|
|
|
|
|
onToggle,
|
|
|
|
|
|
|
|
}): JSX.Element | null => {
|
|
|
|
|
|
|
|
const intl = useIntl();
|
|
|
|
const intl = useIntl();
|
|
|
|
|
|
|
|
const voted = poll.own_votes?.includes(index);
|
|
|
|
if (!poll) return null;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const percent = poll.votes_count === 0 ? 0 : (option.votes_count / poll.votes_count) * 100;
|
|
|
|
|
|
|
|
const leading = poll.options.filterNot(other => other.title === option.title).every(other => option.votes_count >= other.votes_count);
|
|
|
|
|
|
|
|
const voted = poll.own_votes?.includes(index);
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const handleOptionChange = (): void => {
|
|
|
|
const handleOptionChange = (): void => {
|
|
|
|
onToggle(index);
|
|
|
|
onToggle(index);
|
|
|
@ -79,43 +60,65 @@ const PollOption: React.FC<IPollOption> = ({
|
|
|
|
}
|
|
|
|
}
|
|
|
|
};
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
|
|
|
|
<label className={classNames('poll__text', { selectable: !showResults })}>
|
|
|
|
|
|
|
|
<input
|
|
|
|
|
|
|
|
name='vote-options'
|
|
|
|
|
|
|
|
type={poll.multiple ? 'checkbox' : 'radio'}
|
|
|
|
|
|
|
|
value={index}
|
|
|
|
|
|
|
|
checked={active}
|
|
|
|
|
|
|
|
onChange={handleOptionChange}
|
|
|
|
|
|
|
|
disabled={disabled}
|
|
|
|
|
|
|
|
/>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
{!showResults && (
|
|
|
|
|
|
|
|
<span
|
|
|
|
|
|
|
|
className={classNames('poll__input', { checkbox: poll.multiple, active })}
|
|
|
|
|
|
|
|
tabIndex={0}
|
|
|
|
|
|
|
|
role={poll.multiple ? 'checkbox' : 'radio'}
|
|
|
|
|
|
|
|
onKeyPress={handleOptionKeyPress}
|
|
|
|
|
|
|
|
aria-checked={active}
|
|
|
|
|
|
|
|
aria-label={option.title}
|
|
|
|
|
|
|
|
data-index={index}
|
|
|
|
|
|
|
|
/>
|
|
|
|
|
|
|
|
)}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
{showResults && (
|
|
|
|
|
|
|
|
<span className='poll__number' title={intl.formatMessage(messages.votes, { votes: option.votes_count })}>
|
|
|
|
|
|
|
|
{!!voted && <Icon src={require('@tabler/icons/icons/check.svg')} className='poll__vote__mark' title={intl.formatMessage(messages.voted)} />}
|
|
|
|
|
|
|
|
{Math.round(percent)}%
|
|
|
|
|
|
|
|
</span>
|
|
|
|
|
|
|
|
)}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<span dangerouslySetInnerHTML={{ __html: option.title_emojified }} />
|
|
|
|
|
|
|
|
</label>
|
|
|
|
|
|
|
|
);
|
|
|
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
interface IPollOption {
|
|
|
|
|
|
|
|
poll: PollEntity,
|
|
|
|
|
|
|
|
option: PollOptionEntity,
|
|
|
|
|
|
|
|
index: number,
|
|
|
|
|
|
|
|
showResults?: boolean,
|
|
|
|
|
|
|
|
disabled?: boolean,
|
|
|
|
|
|
|
|
active: boolean,
|
|
|
|
|
|
|
|
onToggle: (value: number) => void,
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const PollOption: React.FC<IPollOption> = (props): JSX.Element | null => {
|
|
|
|
|
|
|
|
const { poll, option, showResults } = props;
|
|
|
|
|
|
|
|
if (!poll) return null;
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const percent = poll.votes_count === 0 ? 0 : (option.votes_count / poll.votes_count) * 100;
|
|
|
|
|
|
|
|
const leading = poll.options.filterNot(other => other.title === option.title).every(other => option.votes_count >= other.votes_count);
|
|
|
|
|
|
|
|
|
|
|
|
return (
|
|
|
|
return (
|
|
|
|
<li key={option.title}>
|
|
|
|
<li key={option.title}>
|
|
|
|
{showResults && (
|
|
|
|
{showResults && (
|
|
|
|
<PollPercentageBar percent={percent} leading={leading} />
|
|
|
|
<PollPercentageBar percent={percent} leading={leading} />
|
|
|
|
)}
|
|
|
|
)}
|
|
|
|
|
|
|
|
|
|
|
|
<label className={classNames('poll__text', { selectable: !showResults })}>
|
|
|
|
<PollOptionText percent={percent} {...props} />
|
|
|
|
<input
|
|
|
|
|
|
|
|
name='vote-options'
|
|
|
|
|
|
|
|
type={poll.multiple ? 'checkbox' : 'radio'}
|
|
|
|
|
|
|
|
value={index}
|
|
|
|
|
|
|
|
checked={active}
|
|
|
|
|
|
|
|
onChange={handleOptionChange}
|
|
|
|
|
|
|
|
disabled={disabled}
|
|
|
|
|
|
|
|
/>
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
{!showResults && (
|
|
|
|
|
|
|
|
<span
|
|
|
|
|
|
|
|
className={classNames('poll__input', { checkbox: poll.multiple, active })}
|
|
|
|
|
|
|
|
tabIndex={0}
|
|
|
|
|
|
|
|
role={poll.multiple ? 'checkbox' : 'radio'}
|
|
|
|
|
|
|
|
onKeyPress={handleOptionKeyPress}
|
|
|
|
|
|
|
|
aria-checked={active}
|
|
|
|
|
|
|
|
aria-label={option.title}
|
|
|
|
|
|
|
|
data-index={index}
|
|
|
|
|
|
|
|
/>
|
|
|
|
|
|
|
|
)}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
{showResults && (
|
|
|
|
|
|
|
|
<span className='poll__number' title={intl.formatMessage(messages.votes, { votes: option.votes_count })}>
|
|
|
|
|
|
|
|
{!!voted && <Icon src={require('@tabler/icons/icons/check.svg')} className='poll__vote__mark' title={intl.formatMessage(messages.voted)} />}
|
|
|
|
|
|
|
|
{Math.round(percent)}%
|
|
|
|
|
|
|
|
</span>
|
|
|
|
|
|
|
|
)}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
<span dangerouslySetInnerHTML={{ __html: option.title_emojified }} />
|
|
|
|
|
|
|
|
</label>
|
|
|
|
|
|
|
|
</li>
|
|
|
|
</li>
|
|
|
|
);
|
|
|
|
);
|
|
|
|
};
|
|
|
|
};
|
|
|
|