import React, { useState, useEffect } from 'react'; import { useNavigate } from '@tanstack/react-router'; import { Search, User, Folder, Clock, X, History, ChevronDown } from 'lucide-react'; import { useQuery } from '@tanstack/react-query'; import { api } from '../lib/api'; interface SearchResult { id: string; type: 'customer' | 'project' | 'time-entry'; label: string; subtitle?: string; } export default function SearchBar() { const [query, setQuery] = useState(''); const [isOpen, setIsOpen] = useState(false); const [history, setHistory] = useState([]); const [limit, setLimit] = useState(10); const navigate = useNavigate(); useEffect(() => { const saved = localStorage.getItem('search_history'); if (saved) { try { setHistory(JSON.parse(saved)); } catch (e) { console.error('Failed to parse search history'); } } }, []); const addToHistory = (term: string) => { if (!term.trim()) return; const updated = [term, ...history.filter((item) => item !== term)].slice(0, 10); setHistory(updated); localStorage.setItem('search_history', JSON.stringify(updated)); }; const { data: results, isLoading } = useQuery({ queryKey: ['search', query, limit], queryFn: async () => { if (query.length >= 2) { addToHistory(query); } return api.search(query, limit); }, enabled: query.length >= 2, }); useEffect(() => { const handleKeyDown = (e: KeyboardEvent) => { if (e.key === 'Escape') setIsOpen(false); if ((e.metaKey || e.ctrlKey) && e.key === 'k') { e.preventDefault(); setIsOpen(true); } }; window.addEventListener('keydown', handleKeyDown); return () => window.removeEventListener('keydown', handleKeyDown); }, []); const handleSelect = (result: SearchResult) => { const paths: Record = { customer: `/customers/${result.id}`, project: `/projects/${result.id}`, 'time-entry': `/time-entries/${result.id}`, }; navigate({ to: paths[result.type] }); setQuery(''); setIsOpen(false); }; const handleHistoryClick = (term: string) => { setQuery(term); setIsOpen(true); }; const getIcon = (type: SearchResult['type']) => { switch (type) { case 'customer': return ; case 'project': return ; case 'time-entry': return ; } }; return (
{ setQuery(e.target.value); setLimit(10); setIsOpen(true); }} onFocus={() => setIsOpen(true)} /> {query && ( )}
{isOpen && (
{query.length === 0 ? (
Recent Searches
{history.length > 0 ? ( history.map((term) => ( )) ) : (
No recent searches
)}
) : (
{isLoading ? (
Searching...
) : results && results.length > 0 ? ( <> {results.map((result: SearchResult) => ( ))} {results.length >= limit && ( )} ) : (
No results found
)}
)}
)}
); }