From 2fb6471a685bec1433be3335f377a1a2313e4820 Mon Sep 17 00:00:00 2001 From: nsfisis Date: Thu, 1 Jan 2026 23:44:50 +0900 Subject: refactor(client): migrate API calls to typed RPC client MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Replace raw fetch() calls with apiClient.rpc typed client across all modal and page components. This provides better type safety and eliminates manual auth header handling. - Make handleResponse public for component usage - Update all component tests to mock RPC methods instead of fetch - Change POSTGRES_HOST default to kioku-db for Docker compatibility 🤖 Generated with [Claude Code](https://claude.com/claude-code) Co-Authored-By: Claude Opus 4.5 --- src/client/components/ImportNotesModal.tsx | 60 +++++++----------------------- 1 file changed, 14 insertions(+), 46 deletions(-) (limited to 'src/client/components/ImportNotesModal.tsx') diff --git a/src/client/components/ImportNotesModal.tsx b/src/client/components/ImportNotesModal.tsx index b49b276..a7a88c5 100644 --- a/src/client/components/ImportNotesModal.tsx +++ b/src/client/components/ImportNotesModal.tsx @@ -73,34 +73,21 @@ export function ImportNotesModal({ const fetchNoteTypes = useCallback(async () => { try { - const authHeader = apiClient.getAuthHeader(); - if (!authHeader) { - throw new ApiClientError("Not authenticated", 401); - } - - const res = await fetch("/api/note-types", { - headers: authHeader, - }); - - if (!res.ok) { - const errorBody = await res.json().catch(() => ({})); - throw new ApiClientError( - (errorBody as { error?: string }).error || - `Request failed with status ${res.status}`, - res.status, - ); - } - - const data = await res.json(); + const res = await apiClient.rpc.api["note-types"].$get(); + const data = await apiClient.handleResponse<{ + noteTypes: { id: string; name: string }[]; + }>(res); // Fetch details for each note type to get fields const noteTypesWithFields: NoteType[] = []; for (const nt of data.noteTypes) { - const detailRes = await fetch(`/api/note-types/${nt.id}`, { - headers: authHeader, + const detailRes = await apiClient.rpc.api["note-types"][":id"].$get({ + param: { id: nt.id }, }); if (detailRes.ok) { - const detailData = await detailRes.json(); + const detailData = await apiClient.handleResponse<{ + noteType: NoteType; + }>(detailRes); noteTypesWithFields.push(detailData.noteType); } } @@ -247,35 +234,16 @@ export function ImportNotesModal({ setError(null); try { - const authHeader = apiClient.getAuthHeader(); - if (!authHeader) { - throw new ApiClientError("Not authenticated", 401); - } - - const res = await fetch(`/api/decks/${deckId}/notes/import`, { - method: "POST", - headers: { - "Content-Type": "application/json", - ...authHeader, - }, - body: JSON.stringify({ + const res = await apiClient.rpc.api.decks[":deckId"].notes.import.$post({ + param: { deckId }, + json: { notes: validatedRows.map((row) => ({ noteTypeId: row.noteTypeId, fields: row.fields, })), - }), + }, }); - - if (!res.ok) { - const errorBody = await res.json().catch(() => ({})); - throw new ApiClientError( - (errorBody as { error?: string }).error || - `Request failed with status ${res.status}`, - res.status, - ); - } - - const result = await res.json(); + const result = await apiClient.handleResponse(res); setImportResult(result); setPhase("complete"); onImportComplete(); -- cgit v1.2.3-70-g09d2