'use client' import Link from 'next/link' import { useState, useEffect } from 'react' import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card' import { Badge } from '@/components/ui/badge' import { ArrowRight, Link2, RefreshCw, ExternalLink, Users, ChevronDown, ChevronRight, History, Clock } from 'lucide-react' import { getNavigationHistory, NavigationEntry } from '@/lib/navigation-history' interface BacklinkInfo { id: string sourceNoteId: string targetNoteId: string sourceNote: { id: string title: string type: string } } interface RelatedNote { id: string title: string type: string tags: string[] score: number reason: string } interface NoteConnectionsProps { noteId: string backlinks: BacklinkInfo[] outgoingLinks: BacklinkInfo[] relatedNotes: RelatedNote[] coUsedNotes: { noteId: string; title: string; type: string; weight: number }[] } function ConnectionGroup({ title, icon: Icon, notes, emptyMessage, isCollapsed, onToggle, }: { title: string icon: React.ComponentType<{ className?: string }> notes: { id: string; title: string; type: string }[] emptyMessage: string isCollapsed?: boolean onToggle?: () => void }) { if (notes.length === 0 && isCollapsed) { return null } if (notes.length === 0) { return (

{title}

{emptyMessage}

) } return (

{notes.length}

{!isCollapsed && (
{notes.map((note) => ( {note.title} ))}
)}
) } // Deduplicate notes by id, keeping first occurrence function deduplicateById(items: T[]): T[] { const seen = new Set() return items.filter(item => { if (seen.has(item.id)) return false seen.add(item.id) return true }) } export function NoteConnections({ noteId, backlinks, outgoingLinks, relatedNotes, coUsedNotes, }: NoteConnectionsProps) { const [collapsed, setCollapsed] = useState>({}) const [recentVersions, setRecentVersions] = useState<{ id: string; version: number; createdAt: string }[]>([]) const [navigationHistory, setNavigationHistory] = useState([]) useEffect(() => { fetch(`/api/notes/${noteId}/versions`) .then((r) => r.json()) .then((d) => setRecentVersions(d.data?.slice(0, 3) || [])) .catch(() => setRecentVersions([])) }, [noteId]) useEffect(() => { setNavigationHistory(getNavigationHistory()) }, [noteId]) const hasAnyConnections = backlinks.length > 0 || outgoingLinks.length > 0 || relatedNotes.length > 0 || coUsedNotes.length > 0 // Deduplicate all lists to prevent React key warnings const uniqueBacklinks = deduplicateById(backlinks.map((bl) => ({ id: bl.sourceNote.id, title: bl.sourceNote.title, type: bl.sourceNote.type }))) const uniqueOutgoing = deduplicateById(outgoingLinks.map((ol) => ({ id: ol.sourceNote.id, title: ol.sourceNote.title, type: ol.sourceNote.type }))) const uniqueRelated = deduplicateById(relatedNotes.map((rn) => ({ id: rn.id, title: rn.title, type: rn.type }))) const uniqueCoUsed = deduplicateById(coUsedNotes.map((cu) => ({ id: cu.noteId, title: cu.title, type: cu.type }))) const uniqueHistory = deduplicateById(navigationHistory.slice(0, 5).map((entry) => ({ id: entry.noteId, title: entry.title, type: entry.type }))) const toggleCollapsed = (key: string) => { setCollapsed((prev) => ({ ...prev, [key]: !prev[key] })) } if (!hasAnyConnections && recentVersions.length === 0) { return null } return ( Conectado con {/* Backlinks - notes that link TO this note */} toggleCollapsed('backlinks')} /> {/* Outgoing links - notes this note links TO */} toggleCollapsed('outgoing')} /> {/* Related notes - by content similarity and scoring */} toggleCollapsed('related')} /> {/* Co-used notes - often viewed together */} toggleCollapsed('coused')} /> {/* Recent versions */} {recentVersions.length > 0 && (

Versiones recientes

{recentVersions.map((v) => (

v{v.version} - {new Date(v.createdAt).toLocaleDateString()}

))}
)} {/* Navigation history */} {uniqueHistory.length > 0 && ( toggleCollapsed('history')} /> )}
) }