feat(notes): liens internes, onglet Réseau, living blocks et consentement IA
Rend les liens entre notes visibles et persistants (sync NoteLink au save, auto-save, graphe réseau rafraîchi), ajoute living blocks, Memory Echo, recherche globale, consentement IA explicite et consolide les prototypes design en architectural-grid. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -5,7 +5,10 @@ import { useState, useCallback } from 'react'
|
||||
import dynamic from 'next/dynamic'
|
||||
import type { Note } from '@/lib/types'
|
||||
import { NotesEditorialView } from '@/components/notes-editorial-view'
|
||||
import { getNoteById } from '@/app/actions/notes'
|
||||
import { getNoteById, deleteNote, toggleArchive } from '@/app/actions/notes'
|
||||
import { emitNoteChange } from '@/lib/note-change-sync'
|
||||
import { toast } from 'sonner'
|
||||
import { useLanguage } from '@/lib/i18n'
|
||||
|
||||
const NoteEditor = dynamic(
|
||||
() => import('@/components/note-editor').then(m => ({ default: m.NoteEditor })),
|
||||
@@ -16,7 +19,9 @@ interface ArchiveClientProps {
|
||||
notes: Note[]
|
||||
}
|
||||
|
||||
export function ArchiveClient({ notes }: ArchiveClientProps) {
|
||||
export function ArchiveClient({ notes: initialNotes }: ArchiveClientProps) {
|
||||
const { t } = useLanguage()
|
||||
const [notes, setNotes] = useState<Note[]>(initialNotes)
|
||||
const [editingNote, setEditingNote] = useState<{ note: Note; readOnly: boolean } | null>(null)
|
||||
|
||||
const handleOpen = useCallback(async (note: Note, readOnly = false) => {
|
||||
@@ -28,13 +33,45 @@ export function ArchiveClient({ notes }: ArchiveClientProps) {
|
||||
setEditingNote(null)
|
||||
}, [])
|
||||
|
||||
const handleArchiveNote = useCallback(async (note: Note) => {
|
||||
const nextArchived = !note.isArchived
|
||||
if (nextArchived) {
|
||||
setNotes((prev) => prev.filter((n) => n.id !== note.id))
|
||||
}
|
||||
try {
|
||||
await toggleArchive(note.id, nextArchived, { skipRevalidation: true })
|
||||
emitNoteChange({ type: 'updated', note: { ...note, isArchived: nextArchived } })
|
||||
toast.success(
|
||||
nextArchived ? (t('notes.archived') || 'Archivée') : (t('notes.unarchived') || 'Désarchivée')
|
||||
)
|
||||
} catch {
|
||||
if (nextArchived) setNotes((prev) => [note, ...prev])
|
||||
toast.error(t('general.error'))
|
||||
}
|
||||
}, [t])
|
||||
|
||||
const handleDeleteNote = useCallback(async (note: Note) => {
|
||||
setNotes((prev) => prev.filter((n) => n.id !== note.id))
|
||||
try {
|
||||
await deleteNote(note.id, { skipRevalidation: true })
|
||||
emitNoteChange({ type: 'deleted', noteId: note.id, notebookId: note.notebookId })
|
||||
toast.success(t('notes.deleted') || 'Note supprimée')
|
||||
} catch {
|
||||
setNotes((prev) => [note, ...prev])
|
||||
toast.error(t('general.error'))
|
||||
}
|
||||
}, [t])
|
||||
|
||||
if (editingNote) {
|
||||
return (
|
||||
<NoteEditor
|
||||
note={editingNote.note}
|
||||
readOnly={editingNote.readOnly}
|
||||
onClose={handleClose}
|
||||
onNoteSaved={() => {}}
|
||||
onNoteSaved={(saved) => {
|
||||
setNotes((prev) => prev.map((n) => (n.id === saved.id ? { ...n, ...saved } : n)))
|
||||
emitNoteChange({ type: 'updated', note: saved })
|
||||
}}
|
||||
fullPage
|
||||
/>
|
||||
)
|
||||
@@ -44,6 +81,8 @@ export function ArchiveClient({ notes }: ArchiveClientProps) {
|
||||
<NotesEditorialView
|
||||
notes={notes}
|
||||
onOpen={handleOpen}
|
||||
onArchiveNote={handleArchiveNote}
|
||||
onDeleteNote={handleDeleteNote}
|
||||
/>
|
||||
)
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user