"use client" import { useState, useCallback, useMemo, useEffect, useRef } from "react" import { useQueryClient } from "@tanstack/react-query" import type { DocumentsWithMemoriesResponseSchema } from "@repo/validation/api" import type { z } from "zod" import { cn } from "@lib/utils" import { dmSansClassName } from "@/lib/fonts" import { useIsMobile } from "@hooks/use-mobile" import { Dialog, DialogContent, DialogTitle } from "@repo/ui/components/dialog" import { SearchIcon } from "lucide-react" import { DocumentIcon } from "@/components/new/document-icon" type DocumentsResponse = z.infer type DocumentWithMemories = DocumentsResponse["documents"][0] interface DocumentsCommandPaletteProps { open: boolean onOpenChange: (open: boolean) => void projectId: string onOpenDocument: (document: DocumentWithMemories) => void initialSearch?: string } export function DocumentsCommandPalette({ open, onOpenChange, projectId, onOpenDocument, initialSearch = "", }: DocumentsCommandPaletteProps) { const isMobile = useIsMobile() const queryClient = useQueryClient() const [search, setSearch] = useState("") const [selectedIndex, setSelectedIndex] = useState(0) const [documents, setDocuments] = useState([]) const inputRef = useRef(null) const listRef = useRef(null) // Get documents from the existing query cache when dialog opens useEffect(() => { if (open) { const queryData = queryClient.getQueryData<{ pages: DocumentsResponse[] pageParams: number[] }>(["documents-with-memories", projectId]) if (queryData?.pages) { setDocuments(queryData.pages.flatMap((page) => page.documents ?? [])) } setTimeout(() => inputRef.current?.focus(), 0) setSearch(initialSearch) setSelectedIndex(0) } }, [open, queryClient, projectId, initialSearch]) const filteredDocuments = useMemo(() => { if (!search.trim()) return documents const searchLower = search.toLowerCase() return documents.filter((doc) => doc.title?.toLowerCase().includes(searchLower), ) }, [documents, search]) // Reset selection when filtered results change const handleSearchChange = useCallback((value: string) => { setSearch(value) setSelectedIndex(0) }, []) // Scroll selected item into view useEffect(() => { const selectedElement = listRef.current?.querySelector( `[data-index="${selectedIndex}"]`, ) selectedElement?.scrollIntoView({ block: "nearest" }) }, [selectedIndex]) const handleSelect = useCallback( (document: DocumentWithMemories) => { if (!document.id) return onOpenDocument(document) onOpenChange(false) setSearch("") }, [onOpenDocument, onOpenChange], ) const handleKeyDown = useCallback( (e: React.KeyboardEvent) => { if (e.key === "ArrowDown") { e.preventDefault() setSelectedIndex((i) => (i < filteredDocuments.length - 1 ? i + 1 : i)) } else if (e.key === "ArrowUp") { e.preventDefault() setSelectedIndex((i) => (i > 0 ? i - 1 : i)) } else if (e.key === "Enter") { e.preventDefault() const document = filteredDocuments[selectedIndex] if (document) handleSelect(document) } }, [filteredDocuments, selectedIndex, handleSelect], ) return ( Search Documents
handleSearchChange(e.target.value)} className={cn( "flex-1 bg-transparent text-white text-sm placeholder:text-[#737373] outline-none", dmSansClassName(), )} />
{filteredDocuments.length === 0 ? (

No documents found

) : ( filteredDocuments.map((doc, index) => { const isSelected = index === selectedIndex return ( ) }) )}
) }