From 6f030011baf96bccd66dfbe633e685086d784d3c Mon Sep 17 00:00:00 2001 From: Justin Date: Mon, 6 Jun 2022 13:19:45 -0400 Subject: [PATCH] Convert PollForm to TSX --- .../features/compose/components/poll-form.tsx | 213 ++++++++++++++++++ .../features/compose/components/poll_form.js | 213 ------------------ .../compose/containers/poll_form_container.js | 2 +- app/soapbox/locales/defaultMessages.json | 2 +- 4 files changed, 215 insertions(+), 215 deletions(-) create mode 100644 app/soapbox/features/compose/components/poll-form.tsx delete mode 100644 app/soapbox/features/compose/components/poll_form.js diff --git a/app/soapbox/features/compose/components/poll-form.tsx b/app/soapbox/features/compose/components/poll-form.tsx new file mode 100644 index 000000000..040b904c7 --- /dev/null +++ b/app/soapbox/features/compose/components/poll-form.tsx @@ -0,0 +1,213 @@ +'use strict'; + +import classNames from 'classnames'; +import React from 'react'; +import { defineMessages, FormattedMessage, useIntl } from 'react-intl'; + +import AutosuggestInput from 'soapbox/components/autosuggest_input'; +import Icon from 'soapbox/components/icon'; +import IconButton from 'soapbox/components/icon_button'; +import { HStack } from 'soapbox/components/ui'; +import { useAppSelector } from 'soapbox/hooks'; + +const messages = defineMessages({ + option_placeholder: { id: 'compose_form.poll.option_placeholder', defaultMessage: 'Choice {number}' }, + add_option: { id: 'compose_form.poll.add_option', defaultMessage: 'Add a choice' }, + remove_option: { id: 'compose_form.poll.remove_option', defaultMessage: 'Remove this choice' }, + poll_duration: { id: 'compose_form.poll.duration', defaultMessage: 'Poll duration' }, + switchToMultiple: { id: 'compose_form.poll.switch_to_multiple', defaultMessage: 'Change poll to allow multiple choices' }, + switchToSingle: { id: 'compose_form.poll.switch_to_single', defaultMessage: 'Change poll to allow for a single choice' }, + minutes: { id: 'intervals.full.minutes', defaultMessage: '{number, plural, one {# minute} other {# minutes}}' }, + hours: { id: 'intervals.full.hours', defaultMessage: '{number, plural, one {# hour} other {# hours}}' }, + days: { id: 'intervals.full.days', defaultMessage: '{number, plural, one {# day} other {# days}}' }, +}); + +interface IOption { + index: number + isPollMultiple?: boolean + maxChars: number + numOptions: number + onChange(index: number, value: string): void + onClearSuggestions(): void + onFetchSuggestions(token: string): void + onRemove(index: number): void + onRemovePoll(): void + onSuggestionSelected(tokenStart: number, token: string, value: string, key: (string | number)[]): void + onToggleMultiple(): void + suggestions?: any // list + title: string +} + +const Option = (props: IOption) => { + const { + index, + isPollMultiple, + maxChars, + numOptions, + onChange, + onClearSuggestions, + onFetchSuggestions, + onRemove, + onRemovePoll, + onToggleMultiple, + suggestions, + title, + } = props; + + const intl = useIntl(); + + const handleOptionTitleChange = (event: React.ChangeEvent) => onChange(index, event.target.value); + + const handleOptionRemove = () => { + if (numOptions > 2) { + onRemove(index); + } else { + onRemovePoll(); + } + }; + + const handleToggleMultiple = (event: React.MouseEvent | React.KeyboardEvent) => { + event.preventDefault(); + event.stopPropagation(); + + onToggleMultiple(); + }; + + const onSuggestionsClearRequested = () => onClearSuggestions(); + + const handleCheckboxKeypress = (event: React.KeyboardEvent) => { + if (event.key === 'Enter' || event.key === ' ') { + handleToggleMultiple(event); + } + }; + + const onSuggestionsFetchRequested = (token: string) => onFetchSuggestions(token); + + const onSuggestionSelected = (tokenStart: number, token: string, value: string) => + props.onSuggestionSelected(tokenStart, token, value, ['poll', 'options', index]); + + return ( +
  • + + +
    + +
    +
  • + ); +}; + +interface IPollForm { + expiresIn?: number + isMultiple?: boolean + onAddOption(value: string): void + onChangeOption(): void + onChangeSettings(value: string | number | undefined, isMultiple?: boolean): void + onClearSuggestions(): void + onFetchSuggestions(token: string): void + onRemoveOption(): void + onRemovePoll(): void + onSuggestionSelected(tokenStart: number, token: string, value: string, key: (string | number)[]): void + options?: any + suggestions?: any // list +} + +const PollForm = (props: IPollForm) => { + const { + expiresIn, + isMultiple, + onAddOption, + onChangeOption, + onChangeSettings, + onRemoveOption, + options, + ...filteredProps + } = props; + + const intl = useIntl(); + + const pollLimits = useAppSelector((state) => state.instance.getIn(['configuration', 'polls']) as any); + const maxOptions = pollLimits.get('max_options'); + const maxOptionChars = pollLimits.get('max_characters_per_option'); + + const handleAddOption = () => onAddOption(''); + + const handleSelectDuration = (event: React.ChangeEvent) => + onChangeSettings(event.target.value, isMultiple); + + const handleToggleMultiple = () => onChangeSettings(expiresIn, !isMultiple); + + + if (!options) { + return null; + } + + return ( +
    +
      + {options.map((title: string, i: number) => ( +
    + + + {options.size < maxOptions && ( + + )} + + + +
    + ); +}; + +export default PollForm; diff --git a/app/soapbox/features/compose/components/poll_form.js b/app/soapbox/features/compose/components/poll_form.js deleted file mode 100644 index 41b51ca5e..000000000 --- a/app/soapbox/features/compose/components/poll_form.js +++ /dev/null @@ -1,213 +0,0 @@ -'use strict'; - -import classNames from 'classnames'; -import PropTypes from 'prop-types'; -import React from 'react'; -import ImmutablePropTypes from 'react-immutable-proptypes'; -import ImmutablePureComponent from 'react-immutable-pure-component'; -import { defineMessages, injectIntl, FormattedMessage } from 'react-intl'; -import { connect } from 'react-redux'; - -import AutosuggestInput from 'soapbox/components/autosuggest_input'; -import Icon from 'soapbox/components/icon'; -import IconButton from 'soapbox/components/icon_button'; -import { HStack } from 'soapbox/components/ui'; - -const messages = defineMessages({ - option_placeholder: { id: 'compose_form.poll.option_placeholder', defaultMessage: 'Choice {number}' }, - add_option: { id: 'compose_form.poll.add_option', defaultMessage: 'Add a choice' }, - remove_option: { id: 'compose_form.poll.remove_option', defaultMessage: 'Remove this choice' }, - poll_duration: { id: 'compose_form.poll.duration', defaultMessage: 'Poll duration' }, - switchToMultiple: { id: 'compose_form.poll.switch_to_multiple', defaultMessage: 'Change poll to allow multiple choices' }, - switchToSingle: { id: 'compose_form.poll.switch_to_single', defaultMessage: 'Change poll to allow for a single choice' }, - minutes: { id: 'intervals.full.minutes', defaultMessage: '{number, plural, one {# minute} other {# minutes}}' }, - hours: { id: 'intervals.full.hours', defaultMessage: '{number, plural, one {# hour} other {# hours}}' }, - days: { id: 'intervals.full.days', defaultMessage: '{number, plural, one {# day} other {# days}}' }, -}); - -@injectIntl -class Option extends React.PureComponent { - - static propTypes = { - title: PropTypes.string.isRequired, - index: PropTypes.number.isRequired, - isPollMultiple: PropTypes.bool, - onChange: PropTypes.func.isRequired, - onRemove: PropTypes.func.isRequired, - onToggleMultiple: PropTypes.func.isRequired, - suggestions: ImmutablePropTypes.list, - onClearSuggestions: PropTypes.func.isRequired, - onFetchSuggestions: PropTypes.func.isRequired, - onSuggestionSelected: PropTypes.func.isRequired, - intl: PropTypes.object.isRequired, - maxChars: PropTypes.number.isRequired, - onRemovePoll: PropTypes.func.isRequired, - numOptions: PropTypes.number.isRequired, - }; - - handleOptionTitleChange = e => { - this.props.onChange(this.props.index, e.target.value); - }; - - handleOptionRemove = () => { - if (this.props.numOptions > 2) - this.props.onRemove(this.props.index); - else - this.props.onRemovePoll(); - }; - - handleToggleMultiple = e => { - this.props.onToggleMultiple(); - e.preventDefault(); - e.stopPropagation(); - }; - - onSuggestionsClearRequested = () => { - this.props.onClearSuggestions(); - } - - handleCheckboxKeypress = e => { - if (e.key === 'Enter' || e.key === ' ') { - this.handleToggleMultiple(e); - } - } - - onSuggestionsFetchRequested = (token) => { - this.props.onFetchSuggestions(token); - } - - onSuggestionSelected = (tokenStart, token, value) => { - this.props.onSuggestionSelected(tokenStart, token, value, ['poll', 'options', this.props.index]); - } - - render() { - const { isPollMultiple, title, index, maxChars, intl } = this.props; - - return ( -
  • - - -
    - -
    -
  • - ); - } - -} - -class PollForm extends ImmutablePureComponent { - - static propTypes = { - options: ImmutablePropTypes.list, - expiresIn: PropTypes.number, - isMultiple: PropTypes.bool, - onChangeOption: PropTypes.func.isRequired, - onAddOption: PropTypes.func.isRequired, - onRemoveOption: PropTypes.func.isRequired, - onChangeSettings: PropTypes.func.isRequired, - suggestions: ImmutablePropTypes.list, - onClearSuggestions: PropTypes.func.isRequired, - onFetchSuggestions: PropTypes.func.isRequired, - onSuggestionSelected: PropTypes.func.isRequired, - intl: PropTypes.object.isRequired, - maxOptions: PropTypes.number.isRequired, - maxOptionChars: PropTypes.number.isRequired, - maxExpiration: PropTypes.number, - minExpiration: PropTypes.number, - }; - - handleAddOption = () => { - this.props.onAddOption(''); - }; - - handleSelectDuration = e => { - this.props.onChangeSettings(e.target.value, this.props.isMultiple); - }; - - handleToggleMultiple = () => { - this.props.onChangeSettings(this.props.expiresIn, !this.props.isMultiple); - }; - - render() { - const { options, expiresIn, isMultiple, onChangeOption, onRemoveOption, maxOptions, maxOptionChars, intl, ...other } = this.props; - - if (!options) { - return null; - } - - return ( -
    -
      - {options.map((title, i) => ( -
    - - - {options.size < maxOptions && ( - - )} - - - -
    - ); - } - -} - -const mapStateToProps = state => { - const pollLimits = state.getIn(['instance', 'configuration', 'polls']); - - return { - maxOptions: pollLimits.get('max_options'), - maxOptionChars: pollLimits.get('max_characters_per_option'), - maxExpiration: pollLimits.get('max_expiration'), - minExpiration: pollLimits.get('min_expiration'), - }; -}; - -export default injectIntl(connect(mapStateToProps)(PollForm)); diff --git a/app/soapbox/features/compose/containers/poll_form_container.js b/app/soapbox/features/compose/containers/poll_form_container.js index 08d555b5d..a0b00709d 100644 --- a/app/soapbox/features/compose/containers/poll_form_container.js +++ b/app/soapbox/features/compose/containers/poll_form_container.js @@ -6,7 +6,7 @@ import { fetchComposeSuggestions, selectComposeSuggestion, } from '../../../actions/compose'; -import PollForm from '../components/poll_form'; +import PollForm from '../components/poll-form'; const mapStateToProps = state => ({ suggestions: state.getIn(['compose', 'suggestions']), diff --git a/app/soapbox/locales/defaultMessages.json b/app/soapbox/locales/defaultMessages.json index 0ffbfa7cf..cc961bb29 100644 --- a/app/soapbox/locales/defaultMessages.json +++ b/app/soapbox/locales/defaultMessages.json @@ -2411,7 +2411,7 @@ "id": "intervals.full.days" } ], - "path": "app/soapbox/features/compose/components/poll_form.json" + "path": "app/soapbox/features/compose/components/poll-form.json" }, { "descriptors": [