'use client' import { useNoteEditorContext } from './note-editor-context' import { NoteTitleBlock } from './note-title-block' import { NoteContentArea } from './note-content-area' import { NoteMetadataSection } from './note-metadata-section' import { InlinePaywall } from '@/components/settings/inline-paywall' import { EditorImages } from '@/components/editor-images' import { ComparisonModal } from '@/components/comparison-modal' import { FusionModal } from '@/components/fusion-modal' import { ReminderDialog } from '@/components/reminder-dialog' import { ContextualAIChat } from '@/components/contextual-ai-chat' import { MemoryEchoSection } from '@/components/memory-echo-section' import { Dialog, DialogContent, DialogHeader, DialogTitle, DialogFooter, } from '@/components/ui/dialog' import { Input } from '@/components/ui/input' import { Button } from '@/components/ui/button' import { Badge } from '@/components/ui/badge' import { X } from 'lucide-react' import { useLanguage } from '@/lib/i18n' import { cn } from '@/lib/utils' import { toast } from 'sonner' import { Note } from '@/lib/types' import { useState } from 'react' interface NoteEditorDialogProps { onClose: () => void } export function NoteEditorDialog({ onClose }: NoteEditorDialogProps) { const { state, actions, note, readOnly, notebooks, fileInputRef } = useNoteEditorContext() const { t } = useLanguage() const [comparisonSimilarity, setComparisonSimilarity] = useState() const handleSaveAndClose = async () => { await actions.handleSave() onClose() } return (
{t('notes.edit')}

{readOnly ? t('notes.view') : t('notes.edit')}

{readOnly && ( {t('notes.readOnly')} )}
{/* Title */} {/* Title Suggestions */} {!readOnly && state.titleSuggestions.length > 0 && (
{/* TitleSuggestions component */}
)} {/* Images */} {/* Link Previews */} {state.links.length > 0 && (
{state.links.map((link, idx) => (
{link.imageUrl && (
)}

{link.title || link.url}

{link.description &&

{link.description}

} {new URL(link.url).hostname}
))}
)} {/* Content Area */} {state.quotaExceededFeature === 'reformulate' && ( actions.setQuotaExceededFeature(null)} /> )} {/* Metadata Section */} {/* Memory Echo Connections Section */} {!readOnly && ( { setComparisonSimilarity(meta?.similarity) Promise.all(noteIds.map(async (id: string) => { try { const res = await fetch(`/api/notes/${id}`) if (!res.ok) { console.error(`Failed to fetch note ${id}`) return null } const data = await res.json() if (data.success && data.data) { return data.data } return null } catch (error) { console.error(`Error fetching note ${id}:`, error) return null } })) .then(notes => notes.filter((n: any) => n !== null) as Array>) .then(fetchedNotes => { actions.setComparisonNotes(fetchedNotes) }) }} onMergeNotes={async (noteIds: string[]) => { const fetchedNotes = await Promise.all(noteIds.map(async (id: string) => { try { const res = await fetch(`/api/notes/${id}`) if (!res.ok) { console.error(`Failed to fetch note ${id}`) return null } const data = await res.json() if (data.success && data.data) { return data.data } return null } catch (error) { console.error(`Error fetching note ${id}:`, error) return null } })) actions.setFusionNotes(fetchedNotes.filter((n: any) => n !== null) as Array>) }} /> )} {/* Dialog Toolbar - inline for now */}
{/* ── AI Copilot Side Panel ── */} {state.aiOpen && ( actions.setAiOpen(false)} noteTitle={state.title} noteContent={state.content} noteImages={state.allImages} noteId={note.id} onApplyToNote={(newContent: string) => { actions.setPreviousContentForCopilot(state.content) actions.setContent(newContent) }} onUndoLastAction={state.previousContentForCopilot !== null ? () => { if (state.previousContentForCopilot !== null) { actions.setContent(state.previousContentForCopilot) } actions.setPreviousContentForCopilot(null) } : undefined} lastActionApplied={state.previousContentForCopilot !== null} notebooks={notebooks} notebookId={note.notebookId ?? undefined} notebookName={notebooks.find(nb => nb.id === note.notebookId)?.name ?? undefined} /> )} {/* Reminder Dialog */} {/* Link Dialog */} {t('notes.addLink')}
actions.setLinkUrl(e.target.value)} onKeyDown={(e) => { if (e.key === 'Enter') { e.preventDefault() actions.handleAddLink() } }} autoFocus />
{/* Reformulation Modal */} {state.reformulationModal && ( actions.setReformulationModal(null)}> {t('ai.reformulationComparison')}

{t('ai.original')}

{state.reformulationModal.originalText}

{t('ai.reformulated')} ({state.reformulationModal.option})

{state.reformulationModal.reformulatedText}
)} {/* Comparison Modal */} {state.comparisonNotes && state.comparisonNotes.length > 0 && ( { setComparisonSimilarity(undefined) actions.setComparisonNotes([]) }} notes={state.comparisonNotes} similarity={comparisonSimilarity} onMergeNotes={async (noteIds: string[]) => { const fetchedNotes = await Promise.all(noteIds.map(async (id: string) => { try { const res = await fetch(`/api/notes/${id}`) if (!res.ok) return null const data = await res.json() return data.success && data.data ? data.data : null } catch { return null } })) actions.setFusionNotes(fetchedNotes.filter((n): n is Partial => n !== null)) }} /> )} {/* Fusion Modal */} {state.fusionNotes && state.fusionNotes.length > 0 && ( actions.setFusionNotes([])} notes={state.fusionNotes} onConfirmFusion={async ({ title, content }: { title: string; content: string }, options: { keepAllTags: boolean; archiveOriginals: boolean }) => { // Save current first await actions.handleSave() // Use createNote directly since handleMakeCopy doesn't handle fusion const { createNote } = await import('@/app/actions/notes') await createNote({ title, content, labels: options.keepAllTags ? [...new Set(state.fusionNotes.flatMap(n => n.labels || []))] : state.fusionNotes[0].labels || [], color: state.fusionNotes[0].color, type: 'text', isMarkdown: true, autoGenerated: true, aiProvider: 'fusion', notebookId: state.fusionNotes[0].notebookId ?? undefined }) // Archive original notes if option is selected if (options.archiveOriginals) { const { updateNote } = await import('@/app/actions/notes') for (const fusionNote of state.fusionNotes) { if (fusionNote.id) { await updateNote(fusionNote.id, { isArchived: true }) } } } toast.success(t('toast.notesFusionSuccess')) onClose() }} /> )}
) }