import React, { useState, useEffect } from 'react' import { Memory, MemoryCategory } from '@/types' import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogFooter, } from "@/components/ui/dialog" import { Badge } from "@/components/ui/badge" import { Button } from "@/components/ui/button" import { Textarea } from "@/components/ui/textarea" import { Input } from "@/components/ui/input" import { Label } from "@/components/ui/label" import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from "@/components/ui/select" import { Scroll, Calendar, Tag, User, Clock, Edit, Save, X, Loader2, Plus } from "lucide-react" interface MemoryViewModalProps { memory: Memory | null isOpen: boolean onClose: () => void onSave?: (updatedMemory: Memory) => Promise } const MEMORY_CATEGORIES: MemoryCategory[] = [ 'personal', 'work', 'code', 'research', 'conversations', 'preferences' ] function formatTimestamp(timestamp: string): string { try { const date = new Date(timestamp) return date.toLocaleString() } catch (error) { return timestamp } } function extractTitle(content: string, memory?: Memory): string { // Check for LLM-generated title first if (memory?.tags) { const titleTag = memory.tags.find(tag => tag.startsWith('title:')) if (titleTag) { return titleTag.substring(6) // Remove 'title:' prefix } } // Look for markdown headers const headerMatch = content.match(/^#{1,6}\s+(.+)$/m) if (headerMatch) { return headerMatch[1].trim() } // Extract from first meaningful line const lines = content.split('\n').filter(line => line.trim()) if (lines.length > 0) { const firstLine = lines[0].trim() if (firstLine.length > 5 && firstLine.length < 100) { return firstLine } } return content.substring(0, 50) + (content.length > 50 ? '...' : '') } function renderFormattedContent(content: string): React.ReactNode { // Split content into sections for better readability const sections = content.split(/\n\s*\n/).filter(section => section.trim()) return (
{sections.map((section, index) => { const trimmed = section.trim() // Handle headers if (trimmed.match(/^#{1,6}\s/)) { const level = (trimmed.match(/^#+/) || [''])[0].length const text = trimmed.replace(/^#+\s*/, '') const HeaderTag = `h${Math.min(level, 6)}` as keyof JSX.IntrinsicElements return ( {text} ) } // Handle code blocks if (trimmed.startsWith('```')) { const codeContent = trimmed.replace(/^```[\w]*\n?/, '').replace(/```$/, '') return (
              {codeContent}
            
) } // Handle bullet points if (trimmed.match(/^[-*+]\s/)) { const items = trimmed.split('\n').map(line => line.trim()).filter(Boolean) return ( ) } // Handle numbered lists if (trimmed.match(/^\d+\.\s/)) { const items = trimmed.split('\n').map(line => line.trim()).filter(Boolean) return (
    {items.map((item, itemIndex) => (
  1. {item.replace(/^\d+\.\s/, '')}
  2. ))}
) } // Handle regular paragraphs return (

{trimmed}

) })}
) } export function MemoryViewModal({ memory, isOpen, onClose, onSave }: MemoryViewModalProps) { const [isEditMode, setIsEditMode] = useState(false) const [isSaving, setIsSaving] = useState(false) const [editedMemory, setEditedMemory] = useState(null) const [newTag, setNewTag] = useState('') useEffect(() => { if (memory) { setEditedMemory({ ...memory }) } setIsEditMode(false) }, [memory]) if (!memory || !editedMemory) return null const title = extractTitle(memory.content, memory) const visibleTags = (isEditMode ? editedMemory.tags : memory.tags)?.filter(tag => !tag.startsWith('title:') && !tag.startsWith('summary:') ) || [] const handleSave = async () => { if (!onSave || !editedMemory) return setIsSaving(true) try { await onSave(editedMemory) setIsEditMode(false) } catch (error) { console.error('Failed to save memory:', error) } finally { setIsSaving(false) } } const handleCancel = () => { setEditedMemory({ ...memory }) setIsEditMode(false) setNewTag('') } const handleAddTag = () => { if (newTag.trim() && editedMemory) { const updatedTags = [...(editedMemory.tags || []), newTag.trim()] setEditedMemory({ ...editedMemory, tags: updatedTags }) setNewTag('') } } const handleRemoveTag = (tagToRemove: string) => { if (editedMemory) { const updatedTags = (editedMemory.tags || []).filter(tag => tag !== tagToRemove) setEditedMemory({ ...editedMemory, tags: updatedTags }) } } return (
{title} {onSave && !isEditMode && ( )}
{/* Memory Metadata - View Mode */} {!isEditMode && (
{/* Category */} {memory.category && ( {memory.category} )} {/* Priority */} {memory.priority && ( {memory.priority} )} {/* Project */} {memory.project && ( {memory.project} )} {/* Timestamp */} {formatTimestamp(memory.timestamp)} {/* Complexity */} {memory.complexity && ( L{memory.complexity} )}
)} {/* Edit Form - Edit Mode */} {isEditMode && (
{/* Category and Priority */}
{/* Project */}
setEditedMemory({ ...editedMemory, project: e.target.value })} placeholder="Enter project name" />
)} {/* Tags - View Mode */} {!isEditMode && visibleTags.length > 0 && (
{visibleTags.map((tag, index) => ( #{tag} ))}
)} {/* Tags - Edit Mode */} {isEditMode && (
{visibleTags.map((tag, index) => ( {tag} ))}
setNewTag(e.target.value)} onKeyPress={(e) => e.key === 'Enter' && (e.preventDefault(), handleAddTag())} className="flex-1" />
)} {/* Content */}
{isEditMode ? (