diff --git a/explorer/src/components/SearchBar.tsx b/explorer/src/components/SearchBar.tsx index 878cb7ba5a..e41c699927 100644 --- a/explorer/src/components/SearchBar.tsx +++ b/explorer/src/components/SearchBar.tsx @@ -13,14 +13,30 @@ import { import { Cluster, useCluster } from "providers/cluster"; import { useTokenRegistry } from "providers/mints/token-registry"; import { TokenInfoMap } from "@solana/spl-token-registry"; +import { Connection } from "@solana/web3.js"; +import { getDomainInfo, hasDomainSyntax } from "utils/name-service"; + +interface SearchOptions { + label: string; + options: { + label: string; + value: string[]; + pathname: string; + }[]; +} export function SearchBar() { const [search, setSearch] = React.useState(""); + const searchRef = React.useRef(""); + const [searchOptions, setSearchOptions] = React.useState([]); + const [loadingSearch, setLoadingSearch] = React.useState(false); + const [loadingSearchMessage, setLoadingSearchMessage] = + React.useState("loading..."); const selectRef = React.useRef | null>(null); const history = useHistory(); const location = useLocation(); const { tokenRegistry } = useTokenRegistry(); - const { cluster, clusterInfo } = useCluster(); + const { url, cluster, clusterInfo } = useCluster(); const onChange = ( { pathname }: ValueType, @@ -33,7 +49,54 @@ export function SearchBar() { }; const onInputChange = (value: string, { action }: InputActionMeta) => { - if (action === "input-change") setSearch(value); + if (action === "input-change") { + setSearch(value); + } + }; + + React.useEffect(() => { + searchRef.current = search; + setLoadingSearchMessage("Loading..."); + setLoadingSearch(true); + + // builds and sets local search output + const options = buildOptions( + search, + cluster, + tokenRegistry, + clusterInfo?.epochInfo.epoch + ); + + setSearchOptions(options); + + // checking for non local search output + if (hasDomainSyntax(search)) { + // if search input is a potential domain we continue the loading state + domainSearch(options); + } else { + // if search input is not a potential domain we can conclude the search has finished + setLoadingSearch(false); + } + + // eslint-disable-next-line react-hooks/exhaustive-deps + }, [search]); + + // appends domain lookup results to the local search state + const domainSearch = async (options: SearchOptions[]) => { + setLoadingSearchMessage("Looking up domain..."); + const connection = new Connection(url); + const searchTerm = search; + const updatedOptions = await buildDomainOptions( + connection, + search, + options + ); + if (searchRef.current === searchTerm) { + setSearchOptions(updatedOptions); + // after attempting to fetch the domain name we can conclude the loading state + setLoadingSearch(false); + setLoadingSearchMessage("Loading..."); + } }; const resetValue = "" as any; @@ -44,13 +107,9 @@ export function SearchBar() {