import { type FormEvent, useEffect, useState } from "react"; import { ApiClientError, apiClient } from "../api"; interface Deck { id: string; name: string; description: string | null; newCardsPerDay: number; } 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 [error, setError] = useState(null); const [isSubmitting, setIsSubmitting] = useState(false); // Sync form state when deck changes useEffect(() => { if (deck) { setName(deck.name); setDescription(deck.description ?? ""); setError(null); } }, [deck]); const handleClose = () => { setError(null); onClose(); }; const handleSubmit = async (e: FormEvent) => { e.preventDefault(); if (!deck) return; setError(null); setIsSubmitting(true); try { const authHeader = apiClient.getAuthHeader(); if (!authHeader) { throw new ApiClientError("Not authenticated", 401); } const res = await fetch(`/api/decks/${deck.id}`, { method: "PUT", headers: { "Content-Type": "application/json", ...authHeader, }, body: JSON.stringify({ name: name.trim(), description: description.trim() || null, }), }); 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, ); } 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" />