'use client' import { Controller, useForm, useWatch } from 'react-hook-form' import { useEffect, useState } from 'react' import { useQueryClient } from '@tanstack/react-query' import { zodResolver } from '@hookform/resolvers/zod' import { z } from 'zod' import { Dialog, DialogContent, DialogTitle } from '@/components/ui/dialog' import { Button } from '@/components/ui/button' import { useCreateNote, useUpdateNote, useNote } from '@/lib/hooks/use-notes' import { QUERY_KEYS } from '@/lib/api/query-client' import { MarkdownEditor } from '@/components/ui/markdown-editor' import { InlineEdit } from '@/components/common/InlineEdit' import { cn } from "@/lib/utils"; const createNoteSchema = z.object({ title: z.string().optional(), content: z.string().min(1, 'Content is required'), }) type CreateNoteFormData = z.infer interface NoteEditorDialogProps { open: boolean onOpenChange: (open: boolean) => void notebookId: string note?: { id: string; title: string | null; content: string | null } } export function NoteEditorDialog({ open, onOpenChange, notebookId, note }: NoteEditorDialogProps) { const createNote = useCreateNote() const updateNote = useUpdateNote() const queryClient = useQueryClient() const isEditing = Boolean(note) // Ensure note ID has 'note:' prefix for API calls const noteIdWithPrefix = note?.id ? (note.id.includes(':') ? note.id : `note:${note.id}`) : '' const { data: fetchedNote, isLoading: noteLoading } = useNote(noteIdWithPrefix, { enabled: open && !!note?.id }) const isSaving = isEditing ? updateNote.isPending : createNote.isPending const { handleSubmit, control, formState: { errors }, reset, setValue, } = useForm({ resolver: zodResolver(createNoteSchema), defaultValues: { title: '', content: '', }, }) const watchTitle = useWatch({ control, name: 'title' }) const [isEditorFullscreen, setIsEditorFullscreen] = useState(false) useEffect(() => { if (!open) { reset({ title: '', content: '' }) return } const source = fetchedNote ?? note const title = source?.title ?? '' const content = source?.content ?? '' reset({ title, content }) }, [open, note, fetchedNote, reset]) useEffect(() => { if (!open) return const observer = new MutationObserver(() => { setIsEditorFullscreen(!!document.querySelector('.w-md-editor-fullscreen')) }) observer.observe(document.body, { subtree: true, attributes: true, attributeFilter: ['class'] }) return () => observer.disconnect() }, [open]) const onSubmit = async (data: CreateNoteFormData) => { if (note) { await updateNote.mutateAsync({ id: noteIdWithPrefix, data: { title: data.title || undefined, content: data.content, }, }) // Only invalidate notebook-specific queries if we have a notebookId if (notebookId) { queryClient.invalidateQueries({ queryKey: QUERY_KEYS.notes(notebookId) }) } } else { // Creating a note requires a notebookId if (!notebookId) { console.error('Cannot create note without notebook_id') return } await createNote.mutateAsync({ title: data.title || undefined, content: data.content, note_type: 'human', notebook_id: notebookId, }) } reset() onOpenChange(false) } const handleClose = () => { reset() setIsEditorFullscreen(false) onOpenChange(false) } return ( {isEditing ? 'Edit note' : 'Create note'}
{isEditing && noteLoading ? (
Loading note…
) : ( <>
setValue('title', value || '')} placeholder="Add a title..." emptyText="Untitled Note" className="text-xl font-semibold" inputClassName="text-xl font-semibold" />
( )} /> {errors.content && (

{errors.content.message}

)}
)}
) }