Files
Momento/memento-note/lib/query-hooks.ts
Antigravity 91b1201112 refactor: split NoteEditor into focused components + consolidate contexts
Phase 1: NoteEditor Split (64KB → 9 focused components)
- components/note-editor/: types.ts, context, toolbar, title-block,
  content-area, metadata-section, full-page, dialog compositions
- Maintains backwards compatibility via re-export from note-editor.tsx

Phase 2: Context Consolidation (5 → 3 contexts)
- NotebooksContext absorbs LabelContext (labels CRUD)
- EditorUIContext merges HomeViewContext + NotebookDragContext
- Removed: LabelContext, home-view-context, notebook-drag-context

Phase 3: React Query Infrastructure
- Added QueryProvider with @tanstack/react-query
- lib/query-keys.ts: centralized query key definitions
- lib/query-hooks.ts: useNotes, useNotebooksQuery, useLabelsQuery
- lib/use-refresh.ts: hybrid invalidateQueries + triggerRefresh helper
- NotebooksContext: invalidateQueries on mutations (with triggerRefresh fallback)

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-08 14:31:08 +00:00

78 lines
2.6 KiB
TypeScript

'use client'
import { useQueryClient, useMutation, useQuery } from '@tanstack/react-query'
import { queryKeys } from './query-keys'
import type { Note, Notebook, Label } from '@/lib/types'
// Re-export query keys
export { queryKeys }
// ===== useNotes =====
export function useNotes(notebookId?: string | null) {
return useQuery({
queryKey: queryKeys.notes(notebookId),
queryFn: async (): Promise<Note[]> => {
const url = notebookId ? `/api/notes?notebookId=${notebookId}` : '/api/notes'
const res = await fetch(url, { cache: 'no-store', credentials: 'include' })
const data = await res.json()
return data.notes || []
},
})
}
// ===== useNote =====
export function useNote(noteId: string) {
return useQuery({
queryKey: queryKeys.note(noteId),
queryFn: async (): Promise<Note> => {
const res = await fetch(`/api/notes/${noteId}`, { cache: 'no-store', credentials: 'include' })
const data = await res.json()
return data.note || data
},
enabled: !!noteId,
})
}
// ===== useNotebooks =====
export function useNotebooksQuery() {
return useQuery({
queryKey: queryKeys.notebooks(),
queryFn: async (): Promise<Notebook[]> => {
const res = await fetch('/api/notebooks', { cache: 'no-store', credentials: 'include' })
const data = await res.json()
return data.notebooks || []
},
})
}
// ===== useLabels =====
export function useLabelsQuery(notebookId?: string | null) {
return useQuery({
queryKey: queryKeys.labels(notebookId),
queryFn: async (): Promise<Label[]> => {
const url = new URL('/api/labels', window.location.origin)
if (notebookId) url.searchParams.set('notebookId', notebookId)
const res = await fetch(url.toString(), { cache: 'no-store', credentials: 'include' })
const data = await res.json()
return data.data || []
},
})
}
// ===== invalidateHelpers =====
export function invalidateNotes(queryClient: ReturnType<typeof useQueryClient>, notebookId?: string | null) {
queryClient.invalidateQueries({ queryKey: queryKeys.notes(notebookId) })
}
export function invalidateNote(queryClient: ReturnType<typeof useQueryClient>, noteId: string) {
queryClient.invalidateQueries({ queryKey: queryKeys.note(noteId) })
}
export function invalidateNotebooks(queryClient: ReturnType<typeof useQueryClient>) {
queryClient.invalidateQueries({ queryKey: queryKeys.notebooks() })
}
export function invalidateLabels(queryClient: ReturnType<typeof useQueryClient>, notebookId?: string | null) {
queryClient.invalidateQueries({ queryKey: queryKeys.labels(notebookId) })
}