From 023d0fcfce575030ee503c5f60df8c28dba7ab07 Mon Sep 17 00:00:00 2001 From: nsfisis Date: Sat, 2 May 2026 11:46:13 +0900 Subject: feat(decks): make deck CRUD work fully offline-first MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Create / Edit / Delete deck modals now write through localDeckRepository and fire-and-forget syncActionAtom so the change is pushed when the network is up. EditDeckModal reads its note-type list from the local-first noteTypesAtom instead of fetching, and the "reconnect to..." guards on the submit buttons are gone — the user can keep working while offline. Soft-delete intentionally does NOT cascade to notes/cards, matching the server's existing deck.softDelete: the deck disappears from listings and its children become unreachable that way. Co-Authored-By: Claude Opus 4.7 (1M context) --- src/client/components/DeleteDeckModal.tsx | 29 +++++++++++++---------------- 1 file changed, 13 insertions(+), 16 deletions(-) (limited to 'src/client/components/DeleteDeckModal.tsx') diff --git a/src/client/components/DeleteDeckModal.tsx b/src/client/components/DeleteDeckModal.tsx index 954431e..5e166fc 100644 --- a/src/client/components/DeleteDeckModal.tsx +++ b/src/client/components/DeleteDeckModal.tsx @@ -1,7 +1,7 @@ -import { useAtomValue } from "jotai"; +import { useSetAtom } from "jotai"; import { useState } from "react"; -import { ApiClientError, apiClient } from "../api"; -import { isOnlineAtom } from "../atoms"; +import { syncActionAtom } from "../atoms"; +import { localDeckRepository } from "../db/repositories"; interface Deck { id: string; @@ -23,7 +23,7 @@ export function DeleteDeckModal({ }: DeleteDeckModalProps) { const [error, setError] = useState(null); const [isDeleting, setIsDeleting] = useState(false); - const isOnline = useAtomValue(isOnlineAtom); + const triggerSync = useSetAtom(syncActionAtom); const handleClose = () => { setError(null); @@ -37,19 +37,17 @@ export function DeleteDeckModal({ setIsDeleting(true); try { - const res = await apiClient.rpc.api.decks[":id"].$delete({ - param: { id: deck.id }, - }); - await apiClient.handleResponse(res); + const deleted = await localDeckRepository.delete(deck.id); + if (!deleted) { + setError("Deck not found."); + return; + } onDeckDeleted(); onClose(); - } catch (err) { - if (err instanceof ApiClientError) { - setError(err.message); - } else { - setError("Failed to delete deck. Please try again."); - } + void triggerSync().catch(() => {}); + } catch { + setError("Failed to delete deck. Please try again."); } finally { setIsDeleting(false); } @@ -132,8 +130,7 @@ export function DeleteDeckModal({