import { MagnifyingGlassIcon, XMarkIcon } from "@heroicons/react/24/outline"; import getAccount from "@hey/helpers/getAccount"; import { type AccountFragment, AccountsOrderBy, type AccountsRequest, PageSize, useAccountsLazyQuery } from "@hey/indexer"; import { useClickAway, useDebounce } from "@uidotdev/usehooks"; import type { MutableRefObject } from "react"; import { useCallback, useEffect, useState } from "react"; import { useLocation, useNavigate, useSearchParams } from "react-router"; import { z } from "zod"; import SingleAccount from "@/components/Shared/Account/SingleAccount"; import Loader from "@/components/Shared/Loader"; import { Card, Form, Input, useZodForm } from "@/components/Shared/UI"; import cn from "@/helpers/cn"; import { useAccountLinkStore } from "@/store/non-persisted/navigation/useAccountLinkStore"; import { useSearchStore } from "@/store/persisted/useSearchStore"; import RecentAccounts from "./RecentAccounts"; interface SearchProps { placeholder?: string; } const ValidationSchema = z.object({ query: z .string() .trim() .min(1, { message: "Enter something to search" }) .max(100, { message: "Query should not exceed 100 characters" }) }); const Search = ({ placeholder = "Search…" }: SearchProps) => { const { pathname } = useLocation(); const navigate = useNavigate(); const [searchParams] = useSearchParams(); const type = searchParams.get("type"); const { setCachedAccount } = useAccountLinkStore(); const { addAccount } = useSearchStore(); const [showDropdown, setShowDropdown] = useState(false); const [accounts, setAccounts] = useState([]); const form = useZodForm({ defaultValues: { query: "" }, schema: ValidationSchema }); const query = form.watch("query"); const debouncedSearchText = useDebounce(query, 500); const handleReset = useCallback(() => { setShowDropdown(false); setAccounts([]); form.reset(); }, [form]); const dropdownRef = useClickAway(() => { handleReset(); }) as MutableRefObject; const [searchAccounts, { loading }] = useAccountsLazyQuery(); const handleSubmit = useCallback( ({ query }: z.infer) => { const search = query.trim(); if (pathname === "/search") { navigate(`/search?q=${encodeURIComponent(search)}&type=${type}`); } else { navigate(`/search?q=${encodeURIComponent(search)}&type=accounts`); } handleReset(); }, [pathname, navigate, type, handleReset] ); const handleShowDropdown = useCallback(() => { setShowDropdown(true); }, []); useEffect(() => { if (pathname !== "/search" && showDropdown && debouncedSearchText) { const request: AccountsRequest = { filter: { searchBy: { localNameQuery: debouncedSearchText } }, orderBy: AccountsOrderBy.BestMatch, pageSize: PageSize.Fifty }; searchAccounts({ variables: { request } }).then((res) => { if (res.data?.accounts?.items) { setAccounts(res.data.accounts.items); } }); } }, [debouncedSearchText]); return (
} iconRight={ } onClick={handleShowDropdown} placeholder={placeholder} type="text" {...form.register("query")} /> {pathname !== "/search" && showDropdown ? (
{!debouncedSearchText && ( )} {loading ? ( ) : ( <> {accounts.map((account) => (
{ setCachedAccount(account); addAccount(account.address); navigate(getAccount(account).link); handleReset(); }} >
))} {accounts.length ? null : (
Try searching for people or keywords
)} )}
) : null}
); }; export default Search;