'use client' import { useState, useEffect } from 'react' import { Dialog, DialogContent } from '@/components/ui/dialog' import { Button } from '@/components/ui/button' import { Input } from '@/components/ui/input' import { Sparkles, X, Search, ArrowRight, Eye } from 'lucide-react' import { cn } from '@/lib/utils' import { useLanguage } from '@/lib/i18n/LanguageProvider' interface ConnectionData { noteId: string title: string | null content: string createdAt: Date similarity: number daysApart: number } interface ConnectionsResponse { connections: ConnectionData[] pagination: { total: number page: number limit: number totalPages: number hasNext: boolean hasPrev: boolean } } interface ConnectionsOverlayProps { isOpen: boolean onClose: () => void noteId: string onOpenNote?: (noteId: string) => void onCompareNotes?: (noteIds: string[]) => void } export function ConnectionsOverlay({ isOpen, onClose, noteId, onOpenNote, onCompareNotes }: ConnectionsOverlayProps) { const { t } = useLanguage() const [connections, setConnections] = useState([]) const [isLoading, setIsLoading] = useState(false) const [error, setError] = useState(null) // Filters and sorting const [searchQuery, setSearchQuery] = useState('') const [sortBy, setSortBy] = useState<'similarity' | 'recent' | 'oldest'>('similarity') const [currentPage, setCurrentPage] = useState(1) // Pagination const [pagination, setPagination] = useState({ total: 0, page: 1, limit: 10, totalPages: 0, hasNext: false, hasPrev: false }) // Fetch connections when overlay opens useEffect(() => { if (isOpen && noteId) { fetchConnections(1) } }, [isOpen, noteId]) const fetchConnections = async (page: number = 1) => { setIsLoading(true) setError(null) try { const res = await fetch(`/api/ai/echo/connections?noteId=${noteId}&page=${page}&limit=10`) if (!res.ok) { throw new Error('Failed to fetch connections') } const data: ConnectionsResponse = await res.json() setConnections(data.connections) setPagination(data.pagination) setCurrentPage(data.pagination.page) } catch (err) { console.error('[ConnectionsOverlay] Failed to fetch:', err) setError(t('memoryEcho.overlay.error')) } finally { setIsLoading(false) } } // Filter and sort connections const filteredConnections = connections .filter(conn => { if (!searchQuery) return true const query = searchQuery.toLowerCase() const title = conn.title?.toLowerCase() || '' const content = conn.content.toLowerCase() return title.includes(query) || content.includes(query) }) .sort((a, b) => { switch (sortBy) { case 'similarity': return b.similarity - a.similarity case 'recent': return new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime() case 'oldest': return new Date(a.createdAt).getTime() - new Date(b.createdAt).getTime() default: return 0 } }) const handlePrevPage = () => { if (pagination.hasPrev) { fetchConnections(currentPage - 1) } } const handleNextPage = () => { if (pagination.hasNext) { fetchConnections(currentPage + 1) } } const handleOpenNote = (connNoteId: string) => { onOpenNote?.(connNoteId) onClose() } return ( {/* Header */}

{t('memoryEcho.editorSection.title', { count: pagination.total })}

{t('memoryEcho.description')}

{/* Filters and Search - Show if 7+ connections */} {pagination.total >= 7 && (
{/* Search */}
setSearchQuery(e.target.value)} className="pl-9" />
{/* Sort dropdown */}
)} {/* Content */}
{isLoading ? (
{t('memoryEcho.overlay.loading')}
) : error ? (
{error}
) : filteredConnections.length === 0 ? (

{t('memoryEcho.overlay.noConnections')}

) : (
{filteredConnections.map((conn) => { const similarityPercentage = Math.round(conn.similarity * 100) const title = conn.title || t('memoryEcho.comparison.untitled') return (

{title}

{similarityPercentage}%

{conn.content}

{onCompareNotes && ( )}
) })}
)}
{/* Footer - Pagination */} {pagination.totalPages > 1 && (
{t('pagination.pageInfo', { current: currentPage, total: pagination.totalPages })}
)} {/* Footer - Action */}
) }