'use client'; import { useMemo, useState } from 'react'; import { CalendarDays, ImageIcon, Loader2, Search } from 'lucide-react'; import { Calendar } from '@/components/ui/calendar'; import { Dialog, DialogContent, DialogHeader, DialogTitle } from '@/components/ui/dialog'; import { Input } from '@/components/ui/input'; import type { ChatMessage } from '@/lib/api'; import { getChatDateKey } from '@/lib/chat-date-utils'; import { getMessagePreviewText } from '@/lib/chat-message-utils'; import { cn } from '@/lib/utils'; export type ChatToolsTab = 'search' | 'calendar' | 'media'; interface ChatToolsDialogProps { open: boolean; onOpenChange: (open: boolean) => void; messages: ChatMessage[]; defaultTab?: ChatToolsTab; getMessagePreview: (message: ChatMessage) => string; getMediaUrl?: (message: ChatMessage) => string | null; onJumpToMessage: (messageId: string) => void; } export function ChatToolsDialog({ open, onOpenChange, messages, defaultTab = 'search', getMessagePreview, getMediaUrl, onJumpToMessage }: ChatToolsDialogProps) { const [tab, setTab] = useState(defaultTab); const [query, setQuery] = useState(''); const [selectedDate, setSelectedDate] = useState(); const messageDates = useMemo(() => { const keys = new Set(); for (const message of messages) { keys.add(getChatDateKey(message.createdAt)); } return keys; }, [messages]); const searchResults = useMemo(() => { const normalized = query.trim().toLowerCase(); if (!normalized) return []; return messages.filter((message) => getMessagePreview(message).toLowerCase().includes(normalized)); }, [getMessagePreview, messages, query]); const mediaMessages = useMemo( () => messages.filter((message) => message.type === 'IMAGE' && message.storageKey), [messages] ); const calendarModifiers = useMemo( () => ({ hasMessages: (date: Date) => messageDates.has(getChatDateKey(date)) }), [messageDates] ); function jumpToDate(date: Date) { const key = getChatDateKey(date); const target = messages.find((message) => getChatDateKey(message.createdAt) === key); if (!target) return; onJumpToMessage(target.id); onOpenChange(false); } function handleOpenChange(next: boolean) { onOpenChange(next); if (next) setTab(defaultTab); } return ( Чат
{( [ { id: 'search' as const, label: 'Поиск', icon: Search }, { id: 'calendar' as const, label: 'Дата', icon: CalendarDays }, { id: 'media' as const, label: 'Медиа', icon: ImageIcon } ] as const ).map((item) => ( ))}
{tab === 'search' ? (
setQuery(event.target.value)} placeholder="Поиск по сообщениям" className="rounded-xl pl-9" />
{!query.trim() ? (

Введите текст для поиска

) : searchResults.length ? (
{searchResults.map((message) => ( ))}
) : (

Ничего не найдено

)}
) : null} {tab === 'calendar' ? (
{ setSelectedDate(date); if (date) jumpToDate(date); }} modifiers={calendarModifiers} modifiersClassNames={{ hasMessages: 'relative after:absolute after:bottom-1 after:left-1/2 after:h-1 after:w-1 after:-translate-x-1/2 after:rounded-full after:bg-[#3390ec]' }} />
{ if (!event.target.value) return; jumpToDate(new Date(`${event.target.value}T12:00:00`)); }} />

Точки под датами означают наличие сообщений в этот день

) : null} {tab === 'media' ? ( mediaMessages.length ? (
{mediaMessages.map((message) => { const url = getMediaUrl?.(message); return ( ); })}
) : (

Медиафайлов пока нет

) ) : null}
); } export function buildMessagePreview(message: ChatMessage, visibleText?: string) { return getMessagePreviewText(message, visibleText); }