import React, { useState, useEffect, useCallback } from 'react';
import { useDebounce } from 'use-debounce';
import { useHotkeys } from 'react-hotkeys-hook';
import { useSearchMessages, type SearchResult } from './hooks/useSearch';
import { Input } from './ui/input';
import { ScrollArea } from './ui/scroll-area';
import { Search, MessageSquare, User, Bot, Settings, ChevronRight, RefreshCw } from 'lucide-react';
import { cn } from '@/lib/utils';
import { Badge } from './ui/badge';
interface GlobalSearchModalProps {
isOpen: boolean;
onClose: () => void;
onNavigateToSession: (sessionId: string, messageIndex?: number) => void;
}
export default function GlobalSearchModal({
isOpen,
onClose,
onNavigateToSession,
}: GlobalSearchModalProps) {
const [searchQuery, setSearchQuery] = useState('');
const [debouncedQuery] = useDebounce(searchQuery, 300);
const [selectedIndex, setSelectedIndex] = useState(0);
// Use TanStack Query for search with debouncing
const { data, isLoading, error } = useSearchMessages(debouncedQuery, undefined, 10, isOpen);
const results = data?.results || [];
const searchError = error?.message ?? null;
// Clamp selectedIndex when results change to prevent out-of-bounds selection
useEffect(() => {
if (selectedIndex >= results.length && results.length > 0) {
setSelectedIndex(results.length - 1);
} else if (results.length === 0) {
setSelectedIndex(0);
}
}, [results.length, selectedIndex]);
const handleResultClick = useCallback(
(result: SearchResult) => {
onNavigateToSession(result.sessionId, result.messageIndex);
onClose();
},
[onNavigateToSession, onClose]
);
// Reset when modal opens/closes
useEffect(() => {
if (isOpen) {
setSearchQuery('');
setSelectedIndex(0);
}
}, [isOpen]);
// Keyboard navigation (using react-hotkeys-hook)
// ArrowDown to navigate down in results
useHotkeys(
'down',
() => {
setSelectedIndex((prev) => Math.min(prev + 1, results.length - 1));
},
{ enabled: isOpen, preventDefault: true },
[isOpen, results.length]
);
// ArrowUp to navigate up in results
useHotkeys(
'up',
() => {
setSelectedIndex((prev) => Math.max(prev - 1, 0));
},
{ enabled: isOpen, preventDefault: true },
[isOpen]
);
// Enter to select current result
useHotkeys(
'enter',
() => {
if (results[selectedIndex]) {
handleResultClick(results[selectedIndex]);
setSelectedIndex(0);
}
},
{ enabled: isOpen, preventDefault: true },
[isOpen, results, selectedIndex, handleResultClick]
);
// Escape to close modal
useHotkeys(
'escape',
() => {
onClose();
},
{ enabled: isOpen, preventDefault: true },
[isOpen, onClose]
);
const getRoleIcon = (role: string) => {
switch (role) {
case 'user':
return
Search Error
{searchError}
Try again or check your connection.
No messages found matching your search.
Try different keywords.
Start typing to search your conversations.