YAS/apps/web/src/notes/NotesPage.tsx
YetAnotherSuite Dev d1906bfdfd feat: wire notes frontend to API with optimistic updates and auto-save
- Node service layer connecting Zustand stores to REST API
- NotesPage fetches notes from API on mount with loading state
- NoteEditor auto-saves title and content with 1.5s debounce
- Optimistic updates with rollback on API errors
- Fallback to local-only mode when API is unavailable
- Proper save status indicators (Unsaved → Saving → Saved)
2026-07-20 22:42:59 +02:00

63 lines
1.8 KiB
TypeScript

import { useEffect } from 'react';
import { Plus } from 'lucide-react';
import { useNotesStore } from '../stores/notes';
import { NoteList } from './NoteList';
import { NoteEditor } from './NoteEditor';
import { Button } from '@yetanother/ui';
import { loadNotes, createNote } from '../lib/node-service';
export function NotesPage() {
const notes = useNotesStore((s) => s.notes);
const setSelectedNoteId = useNotesStore((s) => s.setSelectedNoteId);
const loading = useNotesStore((s) => s.loading);
useEffect(() => {
loadNotes();
}, []);
const handleCreate = async () => {
try {
const note = await createNote({
title: '',
workspaceId: notes[0]?.workspaceId ?? crypto.randomUUID(),
});
setSelectedNoteId(note.id as string);
} catch (err) {
const now = new Date().toISOString();
const fallback = {
id: crypto.randomUUID(),
title: '',
type: 'note' as const,
content: { type: 'doc', content: [{ type: 'paragraph' }] },
plainText: '',
status: 'active' as const,
workspaceId: crypto.randomUUID(),
tags: [],
folderId: null,
createdAt: now,
updatedAt: now,
};
useNotesStore.getState().addNote(fallback);
setSelectedNoteId(fallback.id);
}
};
return (
<div className="flex h-full">
<div className="w-72 border-r flex flex-col bg-background">
<div className="p-3 border-b">
<Button onClick={handleCreate} size="sm" className="w-full gap-2" disabled={loading}>
<Plus className="size-4" />
{loading ? 'Loading...' : 'New Note'}
</Button>
</div>
<NoteList />
</div>
<div className="flex-1">
<NoteEditor />
</div>
</div>
);
}