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 { isOpen: boolean; deck: Deck | null; onClose: () => void; onDeckUpdated: () => void; } export function EditDeckModal({ isOpen, deck, onClose, onDeckUpdated, }: EditDeckModalProps) { const [name, setName] = useState(""); const [description, setDescription] = useState(""); const [defaultNoteTypeId, setDefaultNoteTypeId] = useState( null, ); const [noteTypes, setNoteTypes] = useState([]); const [isLoadingNoteTypes, setIsLoadingNoteTypes] = useState(false); const [error, setError] = useState(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(); }; const handleSubmit = async (e: FormEvent) => { e.preventDefault(); if (!deck) return; setError(null); setIsSubmitting(true); try { const res = await apiClient.rpc.api.decks[":id"].$put({ param: { id: deck.id }, json: { name: name.trim(), description: description.trim() || null, defaultNoteTypeId: defaultNoteTypeId || null, }, }); await apiClient.handleResponse(res); onDeckUpdated(); onClose(); } catch (err) { if (err instanceof ApiClientError) { setError(err.message); } else { setError("Failed to update deck. Please try again."); } } finally { setIsSubmitting(false); } }; if (!isOpen || !deck) { return null; } return (
{ if (e.target === e.currentTarget) { handleClose(); } }} onKeyDown={(e) => { if (e.key === "Escape") { handleClose(); } }} >

Edit Deck

{error && (
{error}
)}
setName(e.target.value)} required maxLength={255} disabled={isSubmitting} className="w-full px-4 py-2.5 bg-ivory border border-border rounded-lg text-slate placeholder-muted transition-all duration-200 hover:border-muted focus:border-primary focus:ring-2 focus:ring-primary/10 disabled:opacity-50 disabled:cursor-not-allowed" />