import { useRouter } from "next/router"; import { Combobox, ComboboxInput, ComboboxOption, ComboboxOptions, Dialog, DialogBackdrop, DialogPanel, } from "@headlessui/react"; import { t } from "@lingui/macro"; import { useState } from "react"; import { HiDocumentText, HiFolder, HiMagnifyingGlass } from "react-icons/hi2"; import { useDebounce } from "~/hooks/useDebounce"; import { useWorkspace } from "~/providers/workspace"; import { api } from "~/utils/api"; type SearchResult = | { publicId: string; title: string; description: string | null; slug: string; updatedAt: Date | null; createdAt: Date; type: "board"; } | { publicId: string; title: string; description: string | null; boardPublicId: string; boardName: string; listName: string; updatedAt: Date | null; createdAt: Date; type: "card"; }; export default function CommandPallette({ isOpen, onClose, }: { isOpen: boolean; onClose: () => void; }) { const [query, setQuery] = useState(""); const { workspace } = useWorkspace(); const router = useRouter(); // Debounce to avoid too many reqs const [debouncedQuery] = useDebounce(query, 300); const { data: searchResults, isLoading, isFetched, isPlaceholderData, } = api.workspace.search.useQuery( { workspacePublicId: workspace.publicId, query: debouncedQuery, }, { enabled: Boolean(workspace.publicId && debouncedQuery.trim().length > 0), placeholderData: (previousData) => previousData, }, ); // Clear results when query is empty, otherwise show search results const results = debouncedQuery.trim().length === 0 ? [] : ((searchResults ?? []) as SearchResult[]); const hasSearched = Boolean(debouncedQuery.trim().length > 0); return ( { onClose(); setQuery(""); }} >
setQuery(event.target.value)} onKeyDown={(event) => { if (event.key === "Enter" && results.length > 0) { event.preventDefault(); // Find the active option or fallback to first option const targetOption = document.querySelector( '[data-headlessui-state*="active"][role="option"]', ) ?? document.querySelector('[role="option"]'); if (targetOption) { (targetOption as HTMLElement).click(); } } }} />
{results.length > 0 && ( {results.map((result) => { const url = result.type === "board" ? `/boards/${result.publicId}` : `/cards/${result.publicId}`; return ( { console.log("clicked", url); void router.push(url); onClose(); setQuery(""); }} >
{result.type === "board" ? ( ) : ( )}
{result.title}
{result.type === "card" && (
{`${t`in`} ${result.boardName} → ${result.listName}`}
)}
); })}
)} {hasSearched && !isLoading && searchResults !== undefined && results.length === 0 && (
{t`No results found for "${debouncedQuery}".`}
)}
); }