From fe9ce637e86b6c5dc86d4848dd38b0f1e8d38bc6 Mon Sep 17 00:00:00 2001 From: Justin Date: Tue, 14 Jun 2022 13:52:08 -0400 Subject: [PATCH 1/4] Correctly autofocus on poll input --- .../features/compose/components/{ => polls}/poll-form.tsx | 4 ++-- .../features/compose/containers/poll_form_container.js | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) rename app/soapbox/features/compose/components/{ => polls}/poll-form.tsx (98%) diff --git a/app/soapbox/features/compose/components/poll-form.tsx b/app/soapbox/features/compose/components/polls/poll-form.tsx similarity index 98% rename from app/soapbox/features/compose/components/poll-form.tsx rename to app/soapbox/features/compose/components/polls/poll-form.tsx index 06d178518..18e096e8e 100644 --- a/app/soapbox/features/compose/components/poll-form.tsx +++ b/app/soapbox/features/compose/components/polls/poll-form.tsx @@ -7,7 +7,7 @@ import AutosuggestInput from 'soapbox/components/autosuggest_input'; import { Button, Divider, HStack, Stack, Text, Toggle } from 'soapbox/components/ui'; import { useAppSelector } from 'soapbox/hooks'; -import DurationSelector from './polls/duration-selector'; +import DurationSelector from './duration-selector'; import type { AutoSuggestion } from 'soapbox/components/autosuggest_input'; @@ -94,7 +94,7 @@ const Option = (props: IOption) => { onSuggestionsClearRequested={onSuggestionsClearRequested} onSuggestionSelected={onSuggestionSelected} searchTokens={[':']} - autoFocus={index === 0} + autoFocus={index === 0 || index >= 2} /> diff --git a/app/soapbox/features/compose/containers/poll_form_container.js b/app/soapbox/features/compose/containers/poll_form_container.js index 04c3b61ee..c6bae9f84 100644 --- a/app/soapbox/features/compose/containers/poll_form_container.js +++ b/app/soapbox/features/compose/containers/poll_form_container.js @@ -10,7 +10,7 @@ import { fetchComposeSuggestions, selectComposeSuggestion, } from '../../../actions/compose'; -import PollForm from '../components/poll-form'; +import PollForm from '../components/polls/poll-form'; const mapStateToProps = state => ({ suggestions: state.getIn(['compose', 'suggestions']), From fb94cb8cd18a3680a31028ddc7fbad2b2f24f447 Mon Sep 17 00:00:00 2001 From: Justin Date: Tue, 14 Jun 2022 14:07:43 -0400 Subject: [PATCH 2/4] Get rid of PollFormContainer --- .../compose/components/compose_form.js | 4 +- .../compose/components/polls/poll-form.tsx | 63 +++++++------------ .../compose/containers/poll_form_container.js | 57 ----------------- 3 files changed, 24 insertions(+), 100 deletions(-) delete mode 100644 app/soapbox/features/compose/containers/poll_form_container.js 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/polls/poll-form.tsx b/app/soapbox/features/compose/components/polls/poll-form.tsx index 18e096e8e..04bee234b 100644 --- a/app/soapbox/features/compose/components/polls/poll-form.tsx +++ b/app/soapbox/features/compose/components/polls/poll-form.tsx @@ -3,9 +3,10 @@ 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 './duration-selector'; @@ -31,12 +32,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 +43,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 +63,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]); + dispatch(selectComposeSuggestion(tokenStart, token, value, ['poll', 'options', index])); } }; @@ -107,42 +104,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 +141,7 @@ const PollForm = (props: IPollForm) => { onRemove={onRemoveOption} maxChars={maxOptionChars} numOptions={options.size} - {...filteredProps} + onRemovePoll={onRemovePoll} /> ))} @@ -211,7 +192,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 c6bae9f84..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/polls/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); From e39c8d6713a68786a149bb8e65644e1ef9e8e5e8 Mon Sep 17 00:00:00 2001 From: Justin Date: Tue, 14 Jun 2022 14:17:35 -0400 Subject: [PATCH 3/4] Add danger-link button --- app/soapbox/components/ui/button/useButtonStyles.ts | 3 ++- app/soapbox/features/compose/components/polls/poll-form.tsx | 4 +--- 2 files changed, 3 insertions(+), 4 deletions(-) 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/polls/poll-form.tsx b/app/soapbox/features/compose/components/polls/poll-form.tsx index 04bee234b..56cbd0d46 100644 --- a/app/soapbox/features/compose/components/polls/poll-form.tsx +++ b/app/soapbox/features/compose/components/polls/poll-form.tsx @@ -1,5 +1,3 @@ -'use strict'; - import React from 'react'; import { defineMessages, FormattedMessage, useIntl } from 'react-intl'; @@ -192,7 +190,7 @@ const PollForm = () => { {/* Remove Poll */}
-
From 97b282e4e466613f52e8cf7b371e6bae1f947c32 Mon Sep 17 00:00:00 2001 From: Justin Date: Tue, 14 Jun 2022 14:19:46 -0400 Subject: [PATCH 4/4] Fix selecting emojis in Poll --- app/soapbox/features/compose/components/polls/poll-form.tsx | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/soapbox/features/compose/components/polls/poll-form.tsx b/app/soapbox/features/compose/components/polls/poll-form.tsx index 56cbd0d46..cfcefc822 100644 --- a/app/soapbox/features/compose/components/polls/poll-form.tsx +++ b/app/soapbox/features/compose/components/polls/poll-form.tsx @@ -66,7 +66,7 @@ const Option = (props: IOption) => { const onSuggestionsFetchRequested = (token: string) => dispatch(fetchComposeSuggestions(token)); const onSuggestionSelected = (tokenStart: number, token: string | null, value: AutoSuggestion) => { - if (token && typeof value === 'string') { + if (token && typeof token === 'string') { dispatch(selectComposeSuggestion(tokenStart, token, value, ['poll', 'options', index])); } };