learning_ai_notes/mobile/src/api/notes.ts
2026-03-10 15:53:57 -07:00

124 lines
2.9 KiB
TypeScript

import { getApiClient } from './client';
import { listWorkspaces, type MobileWorkspace } from './workspaces';
export type MobileNote = {
id: string;
workspaceId: string;
title: string;
body: string;
workspaceName: string;
status: 'draft' | 'active' | 'archived';
updatedAt: string;
};
type NoteDoc = {
id: string;
workspaceId: string;
title: string;
body: string;
status: 'draft' | 'active' | 'archived';
updatedAt: string;
};
type NoteListResponse = {
items: NoteDoc[];
};
type CreateNoteInput = {
id: string;
workspaceId: string;
title: string;
body: string;
tags?: string[];
links?: string[];
};
function generateNoteId(): string {
if (typeof globalThis.crypto?.randomUUID === 'function') {
return globalThis.crypto.randomUUID();
}
return `note-${Date.now()}`;
}
function mapWorkspaceNames(workspaces: MobileWorkspace[]) {
return new Map(workspaces.map((workspace) => [workspace.id, workspace.name]));
}
function toMobileNote(note: NoteDoc, workspaceNames: Map<string, string>): MobileNote {
return {
id: note.id,
workspaceId: note.workspaceId,
title: note.title,
body: note.body,
workspaceName: workspaceNames.get(note.workspaceId) ?? note.workspaceId,
status: note.status,
updatedAt: note.updatedAt,
};
}
export async function listNotes(): Promise<MobileNote[]> {
const [response, workspaces] = await Promise.all([
getApiClient().fetch<NoteListResponse>('/notes'),
listWorkspaces(),
]);
const workspaceNames = mapWorkspaceNames(workspaces);
return response.items.map((note) => toMobileNote(note, workspaceNames));
}
export async function getNote(id: string, workspaceId: string): Promise<MobileNote | null> {
const [note, workspaces] = await Promise.all([
getApiClient().fetch<NoteDoc>(`/notes/${id}?workspaceId=${encodeURIComponent(workspaceId)}`),
listWorkspaces(),
]);
return toMobileNote(note, mapWorkspaceNames(workspaces));
}
export async function createNote(
workspaceId: string,
title: string,
body: string,
): Promise<MobileNote> {
const trimmedTitle = title.trim() || 'Untitled draft';
const payload: CreateNoteInput = {
id: generateNoteId(),
workspaceId,
title: trimmedTitle,
body,
tags: [],
links: [],
};
const [created, workspaces] = await Promise.all([
getApiClient().fetch<NoteDoc>('/notes', {
method: 'POST',
body: JSON.stringify(payload),
}),
listWorkspaces(),
]);
return toMobileNote(created, mapWorkspaceNames(workspaces));
}
export async function updateNote(
id: string,
workspaceId: string,
title: string,
body: string,
): Promise<MobileNote> {
const [updated, workspaces] = await Promise.all([
getApiClient().fetch<NoteDoc>(`/notes/${id}?workspaceId=${encodeURIComponent(workspaceId)}`, {
method: 'PATCH',
body: JSON.stringify({
title,
body,
}),
}),
listWorkspaces(),
]);
return toMobileNote(updated, mapWorkspaceNames(workspaces));
}