From 2fb6471a685bec1433be3335f377a1a2313e4820 Mon Sep 17 00:00:00 2001
From: nsfisis <nsfisis@gmail.com>
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 <noreply@anthropic.com>
---
 src/client/components/EditNoteModal.tsx | 75 ++++++++-------------------------
 1 file changed, 17 insertions(+), 58 deletions(-)

(limited to 'src/client/components/EditNoteModal.tsx')

diff --git a/src/client/components/EditNoteModal.tsx b/src/client/components/EditNoteModal.tsx
index 5bd864d..ac22332 100644
--- a/src/client/components/EditNoteModal.tsx
+++ b/src/client/components/EditNoteModal.tsx
@@ -60,25 +60,10 @@ export function EditNoteModal({
 		setError(null);
 
 		try {
-			const authHeader = apiClient.getAuthHeader();
-			if (!authHeader) {
-				throw new ApiClientError("Not authenticated", 401);
-			}
-
-			const res = await fetch(`/api/note-types/${noteTypeId}`, {
-				headers: authHeader,
+			const res = await apiClient.rpc.api["note-types"][":id"].$get({
+				param: { id: noteTypeId },
 			});
-
-			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 data = await apiClient.handleResponse<{ noteType: NoteType }>(res);
 			setNoteType(data.noteType);
 		} catch (err) {
 			if (err instanceof ApiClientError) {
@@ -98,25 +83,14 @@ export function EditNoteModal({
 		setError(null);
 
 		try {
-			const authHeader = apiClient.getAuthHeader();
-			if (!authHeader) {
-				throw new ApiClientError("Not authenticated", 401);
-			}
-
-			const res = await fetch(`/api/decks/${deckId}/notes/${noteId}`, {
-				headers: authHeader,
+			const res = await apiClient.rpc.api.decks[":deckId"].notes[
+				":noteId"
+			].$get({
+				param: { deckId, noteId },
 			});
-
-			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 data = await apiClient.handleResponse<{
+				note: NoteWithFieldValues;
+			}>(res);
 			setNote(data.note);
 
 			// Initialize field values from note
@@ -176,36 +150,21 @@ export function EditNoteModal({
 		setIsSubmitting(true);
 
 		try {
-			const authHeader = apiClient.getAuthHeader();
-			if (!authHeader) {
-				throw new ApiClientError("Not authenticated", 401);
-			}
-
 			// Trim all field values
 			const trimmedFields: Record<string, string> = {};
 			for (const [fieldId, value] of Object.entries(fieldValues)) {
 				trimmedFields[fieldId] = value.trim();
 			}
 
-			const res = await fetch(`/api/decks/${deckId}/notes/${note.id}`, {
-				method: "PUT",
-				headers: {
-					"Content-Type": "application/json",
-					...authHeader,
-				},
-				body: JSON.stringify({
+			const res = await apiClient.rpc.api.decks[":deckId"].notes[
+				":noteId"
+			].$put({
+				param: { deckId, noteId: note.id },
+				json: {
 					fields: trimmedFields,
-				}),
+				},
 			});
-
-			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,
-				);
-			}
+			await apiClient.handleResponse(res);
 
 			onNoteUpdated();
 			handleClose();
-- 
cgit v1.2.3-70-g09d2

