diff --git a/app/soapbox/components/ui/button/useButtonStyles.ts b/app/soapbox/components/ui/button/useButtonStyles.ts index 4e24c0d43..6f26d8be1 100644 --- a/app/soapbox/components/ui/button/useButtonStyles.ts +++ b/app/soapbox/components/ui/button/useButtonStyles.ts @@ -1,6 +1,6 @@ import classNames from 'classnames'; -type ButtonThemes = 'primary' | 'secondary' | 'ghost' | 'accent' | 'danger' | 'transparent' | 'link' +type ButtonThemes = 'primary' | 'secondary' | 'ghost' | 'accent' | 'danger' | 'transparent' | 'link' | 'danger-link' type ButtonSizes = 'sm' | 'md' | 'lg' type IButtonStyles = { @@ -25,6 +25,7 @@ const useButtonStyles = ({ ghost: 'shadow-none border-gray-200 text-gray-700 bg-white dark:border-slate-700 dark:bg-slate-800 dark:text-slate-200 focus:ring-primary-500 focus:ring-2 focus:ring-offset-2', accent: 'border-transparent text-white bg-accent-500 hover:bg-accent-300 focus:ring-pink-500 focus:ring-2 focus:ring-offset-2', danger: 'border-transparent text-danger-700 bg-danger-100 hover:bg-danger-200 focus:ring-danger-500 focus:ring-2 focus:ring-offset-2', + 'danger-link': 'border-transparent text-accent-500 hover:bg-accent-500 hover:bg-opacity-10', transparent: 'border-transparent text-gray-800 backdrop-blur-sm bg-white/75 hover:bg-white/80', link: 'border-transparent text-primary-600 dark:text-primary-400 hover:bg-primary-100 hover:text-primary-700 dark:hover:bg-slate-900/50', }; diff --git a/app/soapbox/features/compose/components/compose_form.js b/app/soapbox/features/compose/components/compose_form.js index 31e80741c..15b14fadb 100644 --- a/app/soapbox/features/compose/components/compose_form.js +++ b/app/soapbox/features/compose/components/compose_form.js @@ -14,13 +14,13 @@ import Icon from 'soapbox/components/icon'; import { Button } from 'soapbox/components/ui'; import { isMobile } from 'soapbox/is_mobile'; +import PollForm from '../components/polls/poll-form'; import ReplyMentions from '../components/reply_mentions'; import UploadForm from '../components/upload_form'; import Warning from '../components/warning'; import EmojiPickerDropdown from '../containers/emoji_picker_dropdown_container'; import MarkdownButtonContainer from '../containers/markdown_button_container'; import PollButtonContainer from '../containers/poll_button_container'; -import PollFormContainer from '../containers/poll_form_container'; import PrivacyDropdownContainer from '../containers/privacy_dropdown_container'; import QuotedStatusContainer from '../containers/quoted_status_container'; import ReplyIndicatorContainer from '../containers/reply_indicator_container'; @@ -361,7 +361,7 @@ class ComposeForm extends ImmutablePureComponent { !condensed &&
- +
} diff --git a/app/soapbox/features/compose/components/poll-form.tsx b/app/soapbox/features/compose/components/polls/poll-form.tsx similarity index 76% rename from app/soapbox/features/compose/components/poll-form.tsx rename to app/soapbox/features/compose/components/polls/poll-form.tsx index 06d178518..cfcefc822 100644 --- a/app/soapbox/features/compose/components/poll-form.tsx +++ b/app/soapbox/features/compose/components/polls/poll-form.tsx @@ -1,13 +1,12 @@ -'use strict'; - import React from 'react'; import { defineMessages, FormattedMessage, useIntl } from 'react-intl'; +import { addPollOption, changePollOption, changePollSettings, clearComposeSuggestions, fetchComposeSuggestions, removePoll, removePollOption, selectComposeSuggestion } from 'soapbox/actions/compose'; import AutosuggestInput from 'soapbox/components/autosuggest_input'; import { Button, Divider, HStack, Stack, Text, Toggle } from 'soapbox/components/ui'; -import { useAppSelector } from 'soapbox/hooks'; +import { useAppDispatch, useAppSelector } from 'soapbox/hooks'; -import DurationSelector from './polls/duration-selector'; +import DurationSelector from './duration-selector'; import type { AutoSuggestion } from 'soapbox/components/autosuggest_input'; @@ -31,12 +30,8 @@ interface IOption { 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 - suggestions?: any // list title: string } @@ -46,16 +41,16 @@ const Option = (props: IOption) => { maxChars, numOptions, onChange, - onClearSuggestions, - onFetchSuggestions, onRemove, onRemovePoll, - suggestions, title, } = props; + const dispatch = useAppDispatch(); const intl = useIntl(); + const suggestions = useAppSelector((state) => state.compose.get('suggestions')); + const handleOptionTitleChange = (event: React.ChangeEvent) => onChange(index, event.target.value); const handleOptionRemove = () => { @@ -66,13 +61,13 @@ const Option = (props: IOption) => { } }; - const onSuggestionsClearRequested = () => onClearSuggestions(); + const onSuggestionsClearRequested = () => dispatch(clearComposeSuggestions()); - const onSuggestionsFetchRequested = (token: string) => onFetchSuggestions(token); + const onSuggestionsFetchRequested = (token: string) => dispatch(fetchComposeSuggestions(token)); const onSuggestionSelected = (tokenStart: number, token: string | null, value: AutoSuggestion) => { - if (token && typeof value === 'string') { - props.onSuggestionSelected(tokenStart, token, value, ['poll', 'options', index]); + if (token && typeof token === 'string') { + dispatch(selectComposeSuggestion(tokenStart, token, value, ['poll', 'options', index])); } }; @@ -94,7 +89,7 @@ const Option = (props: IOption) => { onSuggestionsClearRequested={onSuggestionsClearRequested} onSuggestionSelected={onSuggestionSelected} searchTokens={[':']} - autoFocus={index === 0} + autoFocus={index === 0 || index >= 2} /> @@ -107,42 +102,26 @@ const Option = (props: IOption) => { ); }; -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 PollForm = () => { + const dispatch = useAppDispatch(); const intl = useIntl(); const pollLimits = useAppSelector((state) => state.instance.getIn(['configuration', 'polls']) as any); + const options = useAppSelector((state) => state.compose.getIn(['poll', 'options'])); + const expiresIn = useAppSelector((state) => state.compose.getIn(['poll', 'expires_in'])); + const isMultiple = useAppSelector((state) => state.compose.getIn(['poll', 'multiple'])); + const maxOptions = pollLimits.get('max_options'); const maxOptionChars = pollLimits.get('max_characters_per_option'); - const handleAddOption = () => onAddOption(''); + const onRemoveOption = (index: number) => dispatch(removePollOption(index)); + const onChangeOption = (index: number, title: string) => dispatch(changePollOption(index, title)); + const handleAddOption = () => dispatch(addPollOption('')); + const onChangeSettings = (expiresIn: string | number | undefined, isMultiple?: boolean) => + dispatch(changePollSettings(expiresIn, isMultiple)); const handleSelectDuration = (value: number) => onChangeSettings(value, isMultiple); const handleToggleMultiple = () => onChangeSettings(expiresIn, !isMultiple); + const onRemovePoll = () => dispatch(removePoll()); if (!options) { return null; @@ -160,7 +139,7 @@ const PollForm = (props: IPollForm) => { onRemove={onRemoveOption} maxChars={maxOptionChars} numOptions={options.size} - {...filteredProps} + onRemovePoll={onRemovePoll} /> ))} @@ -211,7 +190,7 @@ const PollForm = (props: IPollForm) => { {/* Remove Poll */}
-
diff --git a/app/soapbox/features/compose/containers/poll_form_container.js b/app/soapbox/features/compose/containers/poll_form_container.js deleted file mode 100644 index 04c3b61ee..000000000 --- a/app/soapbox/features/compose/containers/poll_form_container.js +++ /dev/null @@ -1,57 +0,0 @@ -import { connect } from 'react-redux'; - -import { - addPollOption, - removePollOption, - changePollOption, - changePollSettings, - removePoll, - clearComposeSuggestions, - fetchComposeSuggestions, - selectComposeSuggestion, -} from '../../../actions/compose'; -import PollForm from '../components/poll-form'; - -const mapStateToProps = state => ({ - suggestions: state.getIn(['compose', 'suggestions']), - options: state.getIn(['compose', 'poll', 'options']), - expiresIn: state.getIn(['compose', 'poll', 'expires_in']), - isMultiple: state.getIn(['compose', 'poll', 'multiple']), -}); - -const mapDispatchToProps = dispatch => ({ - onAddOption(title) { - dispatch(addPollOption(title)); - }, - - onRemoveOption(index) { - dispatch(removePollOption(index)); - }, - - onChangeOption(index, title) { - dispatch(changePollOption(index, title)); - }, - - onChangeSettings(expiresIn, isMultiple) { - dispatch(changePollSettings(expiresIn, isMultiple)); - }, - - onClearSuggestions() { - dispatch(clearComposeSuggestions()); - }, - - onFetchSuggestions(token) { - dispatch(fetchComposeSuggestions(token)); - }, - - onSuggestionSelected(position, token, accountId, path) { - dispatch(selectComposeSuggestion(position, token, accountId, path)); - }, - - onRemovePoll() { - dispatch(removePoll()); - }, - -}); - -export default connect(mapStateToProps, mapDispatchToProps)(PollForm);