Add recent searches in web UI (#26834)

th-downstream
Eugen Rochko 1 year ago committed by GitHub
parent 2ac7f10374
commit 0f8203badd

@ -1,3 +1,7 @@
import { fromJS } from 'immutable';
import { searchHistory } from 'mastodon/settings';
import api from '../api';
import { fetchRelationships } from './accounts';
@ -15,8 +19,7 @@ export const SEARCH_EXPAND_REQUEST = 'SEARCH_EXPAND_REQUEST';
export const SEARCH_EXPAND_SUCCESS = 'SEARCH_EXPAND_SUCCESS';
export const SEARCH_EXPAND_FAIL = 'SEARCH_EXPAND_FAIL';
export const SEARCH_RESULT_CLICK = 'SEARCH_RESULT_CLICK';
export const SEARCH_RESULT_FORGET = 'SEARCH_RESULT_FORGET';
export const SEARCH_HISTORY_UPDATE = 'SEARCH_HISTORY_UPDATE';
export function changeSearch(value) {
return {
@ -170,16 +173,34 @@ export const openURL = (value, history, onFailure) => (dispatch, getState) => {
});
};
export const clickSearchResult = (q, type) => ({
type: SEARCH_RESULT_CLICK,
export const clickSearchResult = (q, type) => (dispatch, getState) => {
const previous = getState().getIn(['search', 'recent']);
const me = getState().getIn(['meta', 'me']);
const current = previous.add(fromJS({ type, q })).takeLast(4);
result: {
type,
q,
},
});
searchHistory.set(me, current.toJS());
dispatch(updateSearchHistory(current));
};
export const forgetSearchResult = q => (dispatch, getState) => {
const previous = getState().getIn(['search', 'recent']);
const me = getState().getIn(['meta', 'me']);
const current = previous.filterNot(result => result.get('q') === q);
export const forgetSearchResult = q => ({
type: SEARCH_RESULT_FORGET,
q,
searchHistory.set(me, current.toJS());
dispatch(updateSearchHistory(current));
};
export const updateSearchHistory = recent => ({
type: SEARCH_HISTORY_UPDATE,
recent,
});
export const hydrateSearch = () => (dispatch, getState) => {
const me = getState().getIn(['meta', 'me']);
const history = searchHistory.get(me);
if (history !== null) {
dispatch(updateSearchHistory(history));
}
};

@ -2,6 +2,7 @@ import { Iterable, fromJS } from 'immutable';
import { hydrateCompose } from './compose';
import { importFetchedAccounts } from './importer';
import { hydrateSearch } from './search';
export const STORE_HYDRATE = 'STORE_HYDRATE';
export const STORE_HYDRATE_LAZY = 'STORE_HYDRATE_LAZY';
@ -20,6 +21,7 @@ export function hydrateStore(rawState) {
});
dispatch(hydrateCompose());
dispatch(hydrateSearch());
dispatch(importFetchedAccounts(Object.values(rawState.accounts)));
};
}

@ -16,6 +16,17 @@ const messages = defineMessages({
placeholderSignedIn: { id: 'search.search_or_paste', defaultMessage: 'Search or paste URL' },
});
const labelForRecentSearch = search => {
switch(search.get('type')) {
case 'account':
return `@${search.get('q')}`;
case 'hashtag':
return `#${search.get('q')}`;
default:
return search.get('q');
}
};
class Search extends PureComponent {
static contextTypes = {
@ -187,12 +198,16 @@ class Search extends PureComponent {
};
handleRecentSearchClick = search => {
const { onChange } = this.props;
const { router } = this.context;
if (search.get('type') === 'account') {
router.history.push(`/@${search.get('q')}`);
} else if (search.get('type') === 'hashtag') {
router.history.push(`/tags/${search.get('q')}`);
} else {
onChange(search.get('q'));
this._submit(search.get('type'));
}
this._unfocus();
@ -221,11 +236,15 @@ class Search extends PureComponent {
}
_submit (type) {
const { onSubmit, openInRoute } = this.props;
const { onSubmit, openInRoute, value, onClickSearchResult } = this.props;
const { router } = this.context;
onSubmit(type);
if (value) {
onClickSearchResult(value, type);
}
if (openInRoute) {
router.history.push('/search');
}
@ -243,7 +262,7 @@ class Search extends PureComponent {
const { recent } = this.props;
return recent.toArray().map(search => ({
label: search.get('type') === 'account' ? `@${search.get('q')}` : `#${search.get('q')}`,
label: labelForRecentSearch(search),
action: () => this.handleRecentSearchClick(search),
@ -359,7 +378,7 @@ class Search extends PureComponent {
{searchEnabled ? (
<div className='search__popout__menu'>
{this.defaultOptions.map(({ key, label, action }, i) => (
<button key={key} onMouseDown={action} className={classNames('search__popout__menu__item', { selected: selectedOption === (options.length + i) })}>
<button key={key} onMouseDown={action} className={classNames('search__popout__menu__item', { selected: selectedOption === ((options.length || recent.size) + i) })}>
{label}
</button>
))}

@ -15,7 +15,7 @@ import Search from '../components/search';
const mapStateToProps = state => ({
value: state.getIn(['search', 'value']),
submitted: state.getIn(['search', 'submitted']),
recent: state.getIn(['search', 'recent']),
recent: state.getIn(['search', 'recent']).reverse(),
});
const mapDispatchToProps = dispatch => ({

@ -14,8 +14,7 @@ import {
SEARCH_SHOW,
SEARCH_EXPAND_REQUEST,
SEARCH_EXPAND_SUCCESS,
SEARCH_RESULT_CLICK,
SEARCH_RESULT_FORGET,
SEARCH_HISTORY_UPDATE,
} from '../actions/search';
const initialState = ImmutableMap({
@ -73,10 +72,8 @@ export default function search(state = initialState, action) {
case SEARCH_EXPAND_SUCCESS:
const results = action.searchType === 'hashtags' ? ImmutableOrderedSet(fromJS(action.results.hashtags)) : action.results[action.searchType].map(item => item.id);
return state.updateIn(['results', action.searchType], list => list.union(results));
case SEARCH_RESULT_CLICK:
return state.update('recent', set => set.add(fromJS(action.result)));
case SEARCH_RESULT_FORGET:
return state.update('recent', set => set.filterNot(result => result.get('q') === action.q));
case SEARCH_HISTORY_UPDATE:
return state.set('recent', ImmutableOrderedSet(fromJS(action.recent)));
default:
return state;
}

@ -46,3 +46,4 @@ export default class Settings {
export const pushNotificationsSetting = new Settings('mastodon_push_notification_data');
export const tagHistory = new Settings('mastodon_tag_history');
export const bannerSettings = new Settings('mastodon_banner_settings');
export const searchHistory = new Settings('mastodon_search_history');
Loading…
Cancel
Save