diff --git a/app/soapbox/actions/search.ts b/app/soapbox/actions/search.ts index e8718d479..a2f165ac0 100644 --- a/app/soapbox/actions/search.ts +++ b/app/soapbox/actions/search.ts @@ -8,9 +8,10 @@ import type { SearchFilter } from 'soapbox/reducers/search'; import type { AppDispatch, RootState } from 'soapbox/store'; import type { APIEntity } from 'soapbox/types/entities'; -const SEARCH_CHANGE = 'SEARCH_CHANGE'; -const SEARCH_CLEAR = 'SEARCH_CLEAR'; -const SEARCH_SHOW = 'SEARCH_SHOW'; +const SEARCH_CHANGE = 'SEARCH_CHANGE'; +const SEARCH_CLEAR = 'SEARCH_CLEAR'; +const SEARCH_SHOW = 'SEARCH_SHOW'; +const SEARCH_RESULTS_CLEAR = 'SEARCH_RESULTS_CLEAR'; const SEARCH_FETCH_REQUEST = 'SEARCH_FETCH_REQUEST'; const SEARCH_FETCH_SUCCESS = 'SEARCH_FETCH_SUCCESS'; @@ -28,7 +29,11 @@ const changeSearch = (value: string) => (dispatch: AppDispatch) => { // If backspaced all the way, clear the search if (value.length === 0) { - return dispatch(clearSearch()); + dispatch(clearSearchResults()); + return dispatch({ + type: SEARCH_CHANGE, + value, + }); } else { return dispatch({ type: SEARCH_CHANGE, @@ -41,6 +46,10 @@ const clearSearch = () => ({ type: SEARCH_CLEAR, }); +const clearSearchResults = () => ({ + type: SEARCH_RESULTS_CLEAR, +}); + const submitSearch = (filter?: SearchFilter) => (dispatch: AppDispatch, getState: () => RootState) => { const value = getState().search.value; @@ -167,6 +176,7 @@ export { SEARCH_CHANGE, SEARCH_CLEAR, SEARCH_SHOW, + SEARCH_RESULTS_CLEAR, SEARCH_FETCH_REQUEST, SEARCH_FETCH_SUCCESS, SEARCH_FETCH_FAIL, @@ -177,6 +187,7 @@ export { SEARCH_ACCOUNT_SET, changeSearch, clearSearch, + clearSearchResults, submitSearch, fetchSearchRequest, fetchSearchSuccess, diff --git a/app/soapbox/features/account/components/header.tsx b/app/soapbox/features/account/components/header.tsx index 3f4d239bf..c9620485b 100644 --- a/app/soapbox/features/account/components/header.tsx +++ b/app/soapbox/features/account/components/header.tsx @@ -74,6 +74,7 @@ const messages = defineMessages({ suggestUser: { id: 'admin.users.actions.suggest_user', defaultMessage: 'Suggest @{name}' }, unsuggestUser: { id: 'admin.users.actions.unsuggest_user', defaultMessage: 'Unsuggest @{name}' }, search: { id: 'account.search', defaultMessage: 'Search from @{name}' }, + searchSelf: { id: 'account.search_self', defaultMessage: 'Search your posts' }, unfollowConfirm: { id: 'confirmations.unfollow.confirm', defaultMessage: 'Unfollow' }, blockConfirm: { id: 'confirmations.block.confirm', defaultMessage: 'Block' }, blockDomainConfirm: { id: 'confirmations.domain_block.confirm', defaultMessage: 'Hide entire domain' }, @@ -378,6 +379,13 @@ const Header: React.FC = ({ account }) => { to: '/settings', icon: require('@tabler/icons/settings.svg'), }); + if (features.searchFromAccount) { + menu.push({ + text: intl.formatMessage(messages.searchSelf, { name: account.username }), + action: onSearch, + icon: require('@tabler/icons/search.svg'), + }); + } menu.push(null); menu.push({ text: intl.formatMessage(messages.mutes), diff --git a/app/soapbox/features/compose/components/search.tsx b/app/soapbox/features/compose/components/search.tsx index ec7c89468..9402b8785 100644 --- a/app/soapbox/features/compose/components/search.tsx +++ b/app/soapbox/features/compose/components/search.tsx @@ -9,6 +9,7 @@ import { useHistory } from 'react-router-dom'; import { changeSearch, clearSearch, + clearSearchResults, setSearchAccount, showSearch, submitSearch, @@ -72,7 +73,7 @@ const Search = (props: ISearch) => { event.preventDefault(); if (value.length > 0 || submitted) { - dispatch(clearSearch()); + dispatch(clearSearchResults()); } }; diff --git a/app/soapbox/features/compose/components/search_results.tsx b/app/soapbox/features/compose/components/search_results.tsx index b1cb833ba..8f8fa5938 100644 --- a/app/soapbox/features/compose/components/search_results.tsx +++ b/app/soapbox/features/compose/components/search_results.tsx @@ -2,7 +2,7 @@ import classNames from 'clsx'; import React, { useEffect, useRef } from 'react'; import { FormattedMessage, defineMessages, useIntl } from 'react-intl'; -import { clearSearch, expandSearch, setFilter } from 'soapbox/actions/search'; +import { expandSearch, setFilter, setSearchAccount } from 'soapbox/actions/search'; import { fetchTrendingStatuses } from 'soapbox/actions/trending_statuses'; import Hashtag from 'soapbox/components/hashtag'; import IconButton from 'soapbox/components/icon_button'; @@ -43,7 +43,7 @@ const SearchResults = () => { const handleLoadMore = () => dispatch(expandSearch(selectedFilter)); - const handleClearSearch = () => dispatch(clearSearch()); + const handleUnsetAccount = () => dispatch(setSearchAccount(null)); const selectFilter = (newActiveFilter: SearchFilter) => dispatch(setFilter(newActiveFilter)); @@ -196,7 +196,7 @@ const SearchResults = () => { <> {filterByAccount ? ( - + ({ - title: state.getIn(['group_editor', 'title']), - description: state.getIn(['group_editor', 'description']), - coverImage: state.getIn(['group_editor', 'coverImage']), - disabled: state.getIn(['group_editor', 'isSubmitting']), -}); - -const mapDispatchToProps = dispatch => ({ - onTitleChange: value => dispatch(changeValue('title', value)), - onDescriptionChange: value => dispatch(changeValue('description', value)), - onCoverImageChange: value => dispatch(changeValue('coverImage', value)), - onSubmit: routerHistory => dispatch(submit(routerHistory)), - reset: () => dispatch(reset()), -}); - -export default @connect(mapStateToProps, mapDispatchToProps) -@injectIntl -@withRouter -class Create extends React.PureComponent { - - static propTypes = { - title: PropTypes.string.isRequired, - description: PropTypes.string.isRequired, - coverImage: PropTypes.object, - disabled: PropTypes.bool, - intl: PropTypes.object.isRequired, - onTitleChange: PropTypes.func.isRequired, - onSubmit: PropTypes.func.isRequired, - reset: PropTypes.func.isRequired, - onDescriptionChange: PropTypes.func.isRequired, - onCoverImageChange: PropTypes.func.isRequired, - history: PropTypes.object, - }; - - constructor(props) { - super(props); - props.reset(); - } - - handleTitleChange = e => { - this.props.onTitleChange(e.target.value); - } - - handleDescriptionChange = e => { - this.props.onDescriptionChange(e.target.value); - } - - handleCoverImageChange = e => { - this.props.onCoverImageChange(e.target.files[0]); - } - - handleSubmit = e => { - e.preventDefault(); - this.props.onSubmit(this.props.history); - } - - render() { - const { title, description, coverImage, disabled, intl } = this.props; - - return ( -
-
- -
-
-