diff options
| author | nsfisis <nsfisis@gmail.com> | 2026-02-25 23:02:35 +0900 |
|---|---|---|
| committer | nsfisis <nsfisis@gmail.com> | 2026-02-25 23:02:35 +0900 |
| commit | 38b8fc0e9927c4146b4c8b309b2bcc644abd63d0 (patch) | |
| tree | f76ba23251645e552fccd201362064b06de50bdd /src/client/components/EditDeckModal.tsx | |
| parent | 7a77e72bb49ed3990a0c4581292a37a8a4f35231 (diff) | |
| download | kioku-38b8fc0e9927c4146b4c8b309b2bcc644abd63d0.tar.gz kioku-38b8fc0e9927c4146b4c8b309b2bcc644abd63d0.tar.zst kioku-38b8fc0e9927c4146b4c8b309b2bcc644abd63d0.zip | |
Allow each deck to specify a default note type that is auto-selected
when creating new notes. Includes DB schema migration, server API
updates, sync layer support, and UI for editing the default in the
deck settings modal.
Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
Diffstat (limited to 'src/client/components/EditDeckModal.tsx')
| -rw-r--r-- | src/client/components/EditDeckModal.tsx | 60 |
1 files changed, 59 insertions, 1 deletions
diff --git a/src/client/components/EditDeckModal.tsx b/src/client/components/EditDeckModal.tsx index 8e95295..9a79de8 100644 --- a/src/client/components/EditDeckModal.tsx +++ b/src/client/components/EditDeckModal.tsx @@ -1,10 +1,16 @@ -import { type FormEvent, useEffect, useState } from "react"; +import { type FormEvent, useCallback, useEffect, useState } from "react"; import { ApiClientError, apiClient } from "../api"; interface Deck { id: string; name: string; description: string | null; + defaultNoteTypeId: string | null; +} + +interface NoteTypeSummary { + id: string; + name: string; } interface EditDeckModalProps { @@ -22,18 +28,45 @@ export function EditDeckModal({ }: EditDeckModalProps) { const [name, setName] = useState(""); const [description, setDescription] = useState(""); + const [defaultNoteTypeId, setDefaultNoteTypeId] = useState<string | null>( + null, + ); + const [noteTypes, setNoteTypes] = useState<NoteTypeSummary[]>([]); + const [isLoadingNoteTypes, setIsLoadingNoteTypes] = useState(false); const [error, setError] = useState<string | null>(null); const [isSubmitting, setIsSubmitting] = useState(false); + const fetchNoteTypes = useCallback(async () => { + setIsLoadingNoteTypes(true); + try { + const res = await apiClient.rpc.api["note-types"].$get(); + const data = await apiClient.handleResponse<{ + noteTypes: NoteTypeSummary[]; + }>(res); + setNoteTypes(data.noteTypes); + } catch { + // Non-critical: note type list is optional + } finally { + setIsLoadingNoteTypes(false); + } + }, []); + // Sync form state when deck changes useEffect(() => { if (deck) { setName(deck.name); setDescription(deck.description ?? ""); + setDefaultNoteTypeId(deck.defaultNoteTypeId); setError(null); } }, [deck]); + useEffect(() => { + if (isOpen) { + fetchNoteTypes(); + } + }, [isOpen, fetchNoteTypes]); + const handleClose = () => { setError(null); onClose(); @@ -52,6 +85,7 @@ export function EditDeckModal({ json: { name: name.trim(), description: description.trim() || null, + defaultNoteTypeId: defaultNoteTypeId || null, }, }); await apiClient.handleResponse(res); @@ -147,6 +181,30 @@ export function EditDeckModal({ /> </div> + <div> + <label + htmlFor="edit-deck-default-note-type" + className="block text-sm font-medium text-slate mb-1.5" + > + Default Note Type{" "} + <span className="text-muted font-normal">(optional)</span> + </label> + <select + id="edit-deck-default-note-type" + value={defaultNoteTypeId ?? ""} + onChange={(e) => setDefaultNoteTypeId(e.target.value || null)} + disabled={isSubmitting || isLoadingNoteTypes} + className="w-full px-4 py-2.5 bg-ivory border border-border rounded-lg text-slate transition-all duration-200 hover:border-muted focus:border-primary focus:ring-2 focus:ring-primary/10 disabled:opacity-50 disabled:cursor-not-allowed" + > + <option value="">None</option> + {noteTypes.map((nt) => ( + <option key={nt.id} value={nt.id}> + {nt.name} + </option> + ))} + </select> + </div> + <div className="flex gap-3 justify-end pt-2"> <button type="button" |
