From 334b45ec7430c6fbc194ea00d3f23af31b116fa0 Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Sat, 26 Mar 2022 18:52:48 -0500 Subject: [PATCH] Polls: break out PollPercentageBar into separate component --- app/soapbox/components/poll.tsx | 196 +++++++++++++++++++------------- 1 file changed, 118 insertions(+), 78 deletions(-) diff --git a/app/soapbox/components/poll.tsx b/app/soapbox/components/poll.tsx index b11925fff..3f7139c30 100644 --- a/app/soapbox/components/poll.tsx +++ b/app/soapbox/components/poll.tsx @@ -1,7 +1,7 @@ import classNames from 'classnames'; import React from 'react'; import ImmutablePureComponent from 'react-immutable-pure-component'; -import { defineMessages, injectIntl, FormattedMessage, IntlShape } from 'react-intl'; +import { defineMessages, injectIntl, useIntl, FormattedMessage, IntlShape } from 'react-intl'; import { spring } from 'react-motion'; import { openModal } from 'soapbox/actions/modals'; @@ -12,7 +12,7 @@ import Motion from 'soapbox/features/ui/util/optional_motion'; import RelativeTimestamp from './relative_timestamp'; -import type { Poll as PollEntity, PollOption } from 'soapbox/types/entities'; +import type { Poll as PollEntity, PollOption as PollOptionEntity } from 'soapbox/types/entities'; const messages = defineMessages({ closed: { id: 'poll.closed', defaultMessage: 'Closed' }, @@ -20,6 +20,106 @@ const messages = defineMessages({ votes: { id: 'poll.votes', defaultMessage: '{votes, plural, one {# vote} other {# votes}}' }, }); +interface IPollPercentageBar { + percent: number, + leading: boolean, +} + +const PollPercentageBar: React.FC = ({ percent, leading }): JSX.Element => { + return ( + + {({ width }) =>( + + )} + + ); +}; + +interface IPollOption { + poll: PollEntity, + option: PollOptionEntity, + index: number, + showResults?: boolean, + disabled?: boolean, + active: boolean, + onToggle: (value: number) => void, +} + +const PollOption: React.FC = ({ + poll, + option, + index, + showResults, + disabled, + active, + onToggle, +}): JSX.Element | null => { + const intl = useIntl(); + + 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 => { + onToggle(index); + }; + + const handleOptionKeyPress = (e: React.KeyboardEvent): void => { + if (e.key === 'Enter' || e.key === ' ') { + onToggle(index); + e.stopPropagation(); + e.preventDefault(); + } + }; + + return ( +
  • + {showResults && ( + + )} + + +
  • + ); +}; + interface IPoll { poll?: PollEntity, intl: IntlShape, @@ -30,16 +130,16 @@ interface IPoll { } interface IPollState { - selected: Record, + selected: Record, } class Poll extends ImmutablePureComponent { state = { - selected: {} as Record, + selected: {} as Record, }; - _toggleOption = (value: string) => { + toggleOption = (value: number) => { const { me, poll } = this.props; if (me) { @@ -52,7 +152,7 @@ class Poll extends ImmutablePureComponent { } this.setState({ selected: tmp }); } else { - const tmp: Record = {}; + const tmp: Record = {}; tmp[value] = true; this.setState({ selected: tmp }); } @@ -61,23 +161,6 @@ class Poll extends ImmutablePureComponent { } } - handleOptionChange = (e: React.ChangeEvent): void => { - this._toggleOption(e.currentTarget.value); - }; - - handleOptionKeyPress = (e: React.KeyboardEvent): void => { - if (e.key === 'Enter' || e.key === ' ') { - const dataIndex = e.currentTarget.getAttribute('data-index'); - - if (dataIndex) { - this._toggleOption(dataIndex); - } - - e.stopPropagation(); - e.preventDefault(); - } - } - handleVote = () => { const { disabled, dispatch, poll } = this.props; if (disabled || !dispatch || !poll) return; @@ -99,60 +182,6 @@ class Poll extends ImmutablePureComponent { dispatch(fetchPoll(poll.id)); }; - renderOption(option: PollOption, optionIndex: number, showResults: boolean): JSX.Element | null { - const { poll, disabled, intl } = this.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); - const active = !!this.state.selected[`${optionIndex}`]; - const voted = poll.own_votes?.includes(optionIndex); - const titleEmojified = option.title_emojified; - - return ( -
  • - {showResults && ( - - {({ width }) => - - } - - )} - - -
  • - ); - } - render() { const { poll, intl } = this.props; @@ -167,7 +196,18 @@ class Poll extends ImmutablePureComponent { return (
      - {poll.options.map((option, i) => this.renderOption(option, i, showResults))} + {poll.options.map((option, i) => ( + + ))}