mirror of
https://github.com/kremalicious/metamask-extension.git
synced 2024-12-12 12:47:14 +01:00
3732c5f71e
ESLint rules have been added to enforce our JSDoc conventions. These rules were introduced by updating `@metamask/eslint-config` to v9. Some of the rules have been disabled because the effort to fix all lint errors was too high. It might be easiest to enable these rules one directory at a time, or one rule at a time. Most of the changes in this PR were a result of running `yarn lint:fix`. There were a handful of manual changes that seemed obvious and simple to make. Anything beyond that and the rule was left disabled.
130 lines
3.8 KiB
JavaScript
130 lines
3.8 KiB
JavaScript
import React, { useState, useEffect, useRef } from 'react';
|
|
import { useSelector } from 'react-redux';
|
|
import PropTypes from 'prop-types';
|
|
import Fuse from 'fuse.js';
|
|
import log from 'loglevel';
|
|
import InputAdornment from '@material-ui/core/InputAdornment';
|
|
import TextField from '../../../../components/ui/text-field';
|
|
import { usePrevious } from '../../../../hooks/usePrevious';
|
|
import { isValidHexAddress } from '../../../../../shared/modules/hexstring-utils';
|
|
import { fetchToken } from '../../swaps.util';
|
|
import { getCurrentChainId } from '../../../../selectors/selectors';
|
|
|
|
const renderAdornment = () => (
|
|
<InputAdornment position="start" style={{ marginRight: '12px' }}>
|
|
<img src="images/search.svg" width="17" height="17" alt="" />
|
|
</InputAdornment>
|
|
);
|
|
|
|
export default function ListItemSearch({
|
|
onSearch,
|
|
error,
|
|
listToSearch = [],
|
|
fuseSearchKeys,
|
|
searchPlaceholderText,
|
|
defaultToAll,
|
|
shouldSearchForImports,
|
|
}) {
|
|
const fuseRef = useRef();
|
|
const [searchQuery, setSearchQuery] = useState('');
|
|
const chainId = useSelector(getCurrentChainId);
|
|
|
|
/**
|
|
* Search a custom token for import based on a contract address.
|
|
*
|
|
* @param {string} contractAddress
|
|
*/
|
|
const handleSearchTokenForImport = async (contractAddress) => {
|
|
setSearchQuery(contractAddress);
|
|
try {
|
|
const token = await fetchToken(contractAddress, chainId);
|
|
if (token) {
|
|
token.primaryLabel = token.symbol;
|
|
token.secondaryLabel = token.name;
|
|
token.notImported = true;
|
|
onSearch({
|
|
searchQuery: contractAddress,
|
|
results: [token],
|
|
});
|
|
return;
|
|
}
|
|
} catch (e) {
|
|
log.error('Token not found, show 0 results.', e);
|
|
}
|
|
onSearch({
|
|
searchQuery: contractAddress,
|
|
results: [], // No token for import found.
|
|
});
|
|
};
|
|
|
|
const handleSearch = async (newSearchQuery) => {
|
|
const trimmedNewSearchQuery = newSearchQuery.trim();
|
|
const validHexAddress = isValidHexAddress(trimmedNewSearchQuery);
|
|
const fuseSearchResult = fuseRef.current.search(newSearchQuery);
|
|
const results =
|
|
defaultToAll && newSearchQuery === '' ? listToSearch : fuseSearchResult;
|
|
if (shouldSearchForImports && results.length === 0 && validHexAddress) {
|
|
await handleSearchTokenForImport(trimmedNewSearchQuery);
|
|
return;
|
|
}
|
|
setSearchQuery(newSearchQuery);
|
|
onSearch({
|
|
searchQuery: newSearchQuery,
|
|
results,
|
|
});
|
|
};
|
|
|
|
useEffect(() => {
|
|
if (!fuseRef.current) {
|
|
fuseRef.current = new Fuse(listToSearch, {
|
|
shouldSort: true,
|
|
threshold: 0.45,
|
|
location: 0,
|
|
distance: 100,
|
|
maxPatternLength: 32,
|
|
minMatchCharLength: 1,
|
|
keys: fuseSearchKeys,
|
|
});
|
|
}
|
|
}, [fuseSearchKeys, listToSearch]);
|
|
|
|
const previousListToSearch = usePrevious(listToSearch ?? []);
|
|
useEffect(() => {
|
|
if (
|
|
fuseRef.current &&
|
|
searchQuery &&
|
|
previousListToSearch !== listToSearch
|
|
) {
|
|
fuseRef.current.setCollection(listToSearch);
|
|
const fuseSearchResult = fuseRef.current.search(searchQuery);
|
|
onSearch({ searchQuery, results: fuseSearchResult });
|
|
}
|
|
}, [listToSearch, searchQuery, onSearch, previousListToSearch]);
|
|
|
|
return (
|
|
<TextField
|
|
data-testid="search-list-items"
|
|
className="searchable-item-list__search"
|
|
placeholder={searchPlaceholderText}
|
|
type="text"
|
|
value={searchQuery}
|
|
onChange={(e) => handleSearch(e.target.value)}
|
|
error={error}
|
|
fullWidth
|
|
startAdornment={renderAdornment()}
|
|
autoComplete="off"
|
|
autoFocus
|
|
/>
|
|
);
|
|
}
|
|
|
|
ListItemSearch.propTypes = {
|
|
onSearch: PropTypes.func,
|
|
error: PropTypes.string,
|
|
listToSearch: PropTypes.array.isRequired,
|
|
fuseSearchKeys: PropTypes.arrayOf(PropTypes.object).isRequired,
|
|
searchPlaceholderText: PropTypes.string,
|
|
defaultToAll: PropTypes.bool,
|
|
shouldSearchForImports: PropTypes.bool,
|
|
};
|