import { SessionSummary } from "@/hooks/use-chat-storage"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Tooltip, TooltipContent, TooltipProvider, TooltipTrigger } from "@/components/ui/tooltip"; import { Trash2, Plus, MessageSquare, Search, X, Loader2, ChevronUp, ChevronDown } from "lucide-react"; import { cn } from "@/lib/utils"; import { useState, useEffect, useRef } from "react"; interface SidebarListProps { sessions: SessionSummary[]; currentSessionId: string | null; onSelectSession: (id: string) => void; onDeleteSession: (id: string) => void; onNewChat: () => void; onSearch?: (query: string) => void; isSearching?: boolean; searchQuery?: string; onNavigateMatch?: (sessionId: string, direction: 'prev' | 'next') => void; } function formatDate(dateString: string) { const date = new Date(dateString); const now = new Date(); const diffInMs = now.getTime() - date.getTime(); const diffInHours = diffInMs / (1000 * 60 * 60); const diffInDays = diffInMs / (1000 * 60 * 60 * 24); // Se foi hoje, mostrar apenas hora if (diffInHours < 24) { return new Intl.DateTimeFormat('pt-BR', { hour: '2-digit', minute: '2-digit' }).format(date); } // Se foi ontem if (diffInDays < 2) { return 'Ontem'; } // Se foi nos últimos 7 dias if (diffInDays < 7) { return new Intl.DateTimeFormat('pt-BR', { weekday: 'short' }).format(date); } // Caso contrário, mostrar data completa return new Intl.DateTimeFormat('pt-BR', { day: '2-digit', month: '2-digit', year: diffInDays > 365 ? 'numeric' : undefined }).format(date); } export function SidebarList({ sessions, currentSessionId, onSelectSession, onDeleteSession, onNewChat, onSearch, isSearching = false, searchQuery = '', onNavigateMatch }: SidebarListProps) { const [localSearchInput, setLocalSearchInput] = useState(''); const searchTimeoutRef = useRef(null); const DEBOUNCE_MS = 300; useEffect(() => { // Limpar timeout anterior if (searchTimeoutRef.current) { clearTimeout(searchTimeoutRef.current); } // Se query vazia, limpar busca imediatamente if (!localSearchInput.trim()) { if (onSearch) { onSearch(''); } return; } // Debounce: aguardar antes de buscar searchTimeoutRef.current = setTimeout(() => { if (onSearch && localSearchInput.trim().length >= 2) { onSearch(localSearchInput.trim()); } }, DEBOUNCE_MS); // Cleanup return () => { if (searchTimeoutRef.current) { clearTimeout(searchTimeoutRef.current); } }; }, [localSearchInput, onSearch]); const handleClearSearch = () => { setLocalSearchInput(''); if (onSearch) { onSearch(''); } }; return (
{/* Header com busca e botão Nova Conversa */}
{/* Campo de busca */}
setLocalSearchInput(e.target.value)} className="pl-8 pr-8 h-9 text-sm" /> {isSearching && ( )} {localSearchInput && !isSearching && ( )}
{/* Botão Nova Conversa */}
{/* Lista de chats com scroll customizado */}
{sessions.length === 0 && (

{searchQuery ? 'Nenhuma conversa encontrada' : 'Nenhuma conversa salva'}

{searchQuery ? 'Tente buscar por outro termo' : 'Comece uma nova conversa para começar'}

)} {sessions.map((session) => { const isSelected = currentSessionId === session.id; const showTooltip = session.title.length > 30; return (
onSelectSession(session.id)} role="button" tabIndex={0} onKeyDown={(e) => { if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); onSelectSession(session.id); } }} > {/* Conteúdo do card */}
{/* Ícone/Emoji */}
{session.emoji || '💬'}
{/* Texto do card */}

{session.title}

{formatDate(session.updated_at)}

{searchQuery && session.match_count !== undefined && session.match_count > 0 && ( {session.match_count} {session.match_count === 1 ? 'ocorrência' : 'ocorrências'} )}
{/* Navegação de matches - aparece apenas quando selecionado e há busca ativa */} {isSelected && searchQuery && session.match_count !== undefined && session.match_count > 0 && onNavigateMatch && (
)} {/* Botão de deletar - aparece no hover */}
{/* Indicador de seleção */} {isSelected && (
)}
{showTooltip && (

{session.title}

{formatDate(session.updated_at)}

)} ); })}
); }