From e6c25a1887dd7a106c4489c1995e347fc9a5f55d Mon Sep 17 00:00:00 2001 From: Alex Gleason Date: Sat, 4 Jun 2022 17:47:40 -0500 Subject: [PATCH] AutosuggestAccountInput: convert to TSX --- app/soapbox/actions/accounts.js | 4 +- .../components/autosuggest_account_input.js | 95 ------------------- .../components/autosuggest_account_input.tsx | 86 +++++++++++++++++ .../features/compose/components/search.tsx | 4 +- 4 files changed, 90 insertions(+), 99 deletions(-) delete mode 100644 app/soapbox/components/autosuggest_account_input.js create mode 100644 app/soapbox/components/autosuggest_account_input.tsx diff --git a/app/soapbox/actions/accounts.js b/app/soapbox/actions/accounts.js index b93f0e599..88306c2ad 100644 --- a/app/soapbox/actions/accounts.js +++ b/app/soapbox/actions/accounts.js @@ -1050,10 +1050,10 @@ export function fetchPinnedAccountsFail(id, error) { }; } -export function accountSearch(params, cancelToken) { +export function accountSearch(params, signal) { return (dispatch, getState) => { dispatch({ type: ACCOUNT_SEARCH_REQUEST, params }); - return api(getState).get('/api/v1/accounts/search', { params, cancelToken }).then(({ data: accounts }) => { + return api(getState).get('/api/v1/accounts/search', { params, signal }).then(({ data: accounts }) => { dispatch(importFetchedAccounts(accounts)); dispatch({ type: ACCOUNT_SEARCH_SUCCESS, accounts }); return accounts; diff --git a/app/soapbox/components/autosuggest_account_input.js b/app/soapbox/components/autosuggest_account_input.js deleted file mode 100644 index fd93f52a9..000000000 --- a/app/soapbox/components/autosuggest_account_input.js +++ /dev/null @@ -1,95 +0,0 @@ -import { CancelToken } from 'axios'; -import { OrderedSet as ImmutableOrderedSet } from 'immutable'; -import { throttle } from 'lodash'; -import PropTypes from 'prop-types'; -import React from 'react'; -import ImmutablePureComponent from 'react-immutable-pure-component'; -import { connect } from 'react-redux'; - -import { accountSearch } from 'soapbox/actions/accounts'; - -import AutosuggestInput from './autosuggest_input'; - -const noOp = () => {}; - -export default @connect() -class AutosuggestAccountInput extends ImmutablePureComponent { - - static propTypes = { - dispatch: PropTypes.func.isRequired, - onChange: PropTypes.func.isRequired, - onSelected: PropTypes.func.isRequired, - value: PropTypes.string.isRequired, - limit: PropTypes.number.isRequired, - } - - static defaultProps = { - value: '', - limit: 4, - } - - state = { - accountIds: ImmutableOrderedSet(), - } - - source = CancelToken.source(); - - refreshCancelToken = () => { - this.source.cancel(); - this.source = CancelToken.source(); - return this.source; - } - - clearResults = () => { - this.setState({ accountIds: ImmutableOrderedSet() }); - } - - handleAccountSearch = throttle(q => { - const { dispatch, limit } = this.props; - const source = this.refreshCancelToken(); - - const params = { q, limit, resolve: false }; - - dispatch(accountSearch(params, source.token)) - .then(accounts => { - const accountIds = accounts.map(account => account.id); - this.setState({ accountIds: ImmutableOrderedSet(accountIds) }); - }) - .catch(noOp); - - }, 900, { leading: true, trailing: true }) - - handleChange = e => { - this.handleAccountSearch(e.target.value); - this.props.onChange(e); - } - - handleSelected = (tokenStart, lastToken, accountId) => { - this.props.onSelected(accountId); - } - - componentDidUpdate(prevProps) { - if (this.props.value === '' && prevProps.value !== '') { - this.clearResults(); - } - } - - render() { - const { intl, value, onChange, ...rest } = this.props; - const { accountIds } = this.state; - - return ( - - ); - } - -} diff --git a/app/soapbox/components/autosuggest_account_input.tsx b/app/soapbox/components/autosuggest_account_input.tsx new file mode 100644 index 000000000..d437e79fc --- /dev/null +++ b/app/soapbox/components/autosuggest_account_input.tsx @@ -0,0 +1,86 @@ +import { OrderedSet as ImmutableOrderedSet } from 'immutable'; +import { throttle } from 'lodash'; +import React, { useState, useRef, useCallback, useEffect } from 'react'; + +import { accountSearch } from 'soapbox/actions/accounts'; +import AutosuggestInput from 'soapbox/components/autosuggest_input'; +import { useAppDispatch } from 'soapbox/hooks'; + +import type { Menu } from 'soapbox/components/dropdown_menu'; + +const noOp = () => {}; + +interface IAutosuggestAccountInput { + onChange: React.ChangeEventHandler, + onSelected: (accountId: string) => void, + value: string, + limit?: number, + className?: string, + autoSelect?: boolean, + menu?: Menu, + onKeyDown?: React.KeyboardEventHandler, +} + +const AutosuggestAccountInput: React.FC = ({ + onChange, + onSelected, + value = '', + limit = 4, + ...rest +}) => { + const dispatch = useAppDispatch(); + const [accountIds, setAccountIds] = useState(ImmutableOrderedSet()); + const controller = useRef(new AbortController()); + + const refreshCancelToken = () => { + controller.current.abort(); + controller.current = new AbortController(); + }; + + const clearResults = () => { + setAccountIds(ImmutableOrderedSet()); + }; + + const handleAccountSearch = useCallback(throttle(q => { + const params = { q, limit, resolve: false }; + + dispatch(accountSearch(params, controller.current.signal)) + .then((accounts: { id: string }[]) => { + const accountIds = accounts.map(account => account.id); + setAccountIds(ImmutableOrderedSet(accountIds)); + }) + .catch(noOp); + + }, 900, { leading: true, trailing: true }), [limit]); + + const handleChange: React.ChangeEventHandler = e => { + refreshCancelToken(); + handleAccountSearch(e.target.value); + onChange(e); + }; + + const handleSelected = (_tokenStart: string, _lastToken: string, accountId: string) => { + onSelected(accountId); + }; + + useEffect(() => { + if (value === '') { + clearResults(); + } + }, [value]); + + return ( + + ); +}; + +export default AutosuggestAccountInput; diff --git a/app/soapbox/features/compose/components/search.tsx b/app/soapbox/features/compose/components/search.tsx index 401001fc9..d68f82bc2 100644 --- a/app/soapbox/features/compose/components/search.tsx +++ b/app/soapbox/features/compose/components/search.tsx @@ -21,7 +21,7 @@ const messages = defineMessages({ action: { id: 'search.action', defaultMessage: 'Search for “{query}”' }, }); -function redirectToAccount(accountId: number, routerHistory: any) { +function redirectToAccount(accountId: string, routerHistory: any) { return (_dispatch: any, getState: () => ImmutableMap) => { const acct = getState().getIn(['accounts', accountId, 'acct']); @@ -97,7 +97,7 @@ const Search = (props: ISearch) => { dispatch(showSearch()); }; - const handleSelected = (accountId: number) => { + const handleSelected = (accountId: string) => { dispatch(clearSearch()); dispatch(redirectToAccount(accountId, history)); };