/** * Component: Manage Shelf Modal * Documentation: documentation/frontend/components.md */ 'use client'; import React, { useState } from 'react'; import { Modal } from './Modal'; import { GenericShelf } from '@/lib/hooks/useShelves'; import { useUpdateGoodreadsShelf } from '@/lib/hooks/useGoodreadsShelves'; import { useUpdateHardcoverShelf } from '@/lib/hooks/useHardcoverShelves'; import { cn } from '@/lib/utils/cn'; interface ManageShelfModalProps { shelf: GenericShelf | null; isOpen: boolean; onClose: () => void; } export function ManageShelfModal({ shelf, isOpen, onClose }: ManageShelfModalProps) { const [rssUrl, setRssUrl] = useState(''); const [listId, setListId] = useState(''); const [apiToken, setApiToken] = useState(''); const { updateShelf: updateGoodreads, isLoading: isUpdatingGoodreads, error: goodreadsError } = useUpdateGoodreadsShelf(); const { updateShelf: updateHardcover, isLoading: isUpdatingHardcover, error: hardcoverError } = useUpdateHardcoverShelf(); // Reset form when shelf changes (use shelf?.id for stable reference) React.useEffect(() => { if (shelf) { setRssUrl(shelf.type === 'goodreads' ? shelf.sourceId : ''); setListId(shelf.type === 'hardcover' ? shelf.sourceId : ''); setApiToken(''); } }, [shelf?.id]); if (!shelf) return null; const isUpdating = isUpdatingGoodreads || isUpdatingHardcover; const currentError = shelf.type === 'goodreads' ? goodreadsError : hardcoverError; const handleSubmit = async (e: React.FormEvent) => { e.preventDefault(); try { if (shelf.type === 'goodreads') { if (!rssUrl.trim()) return; await updateGoodreads(shelf.id, { rssUrl: rssUrl.trim() }); } else { if (!listId.trim()) return; await updateHardcover(shelf.id, { listId: listId.trim(), apiToken: apiToken.trim() || undefined, forceSync: true, }); } onClose(); } catch (err) { // Error is handled by hook } }; const isGoodreads = shelf.type === 'goodreads'; return (
{currentError && (

{currentError}

)}
{isGoodreads ? (
setRssUrl(e.target.value)} placeholder="https://www.goodreads.com/review/list_rss/..." className="w-full px-4 py-2 bg-gray-50 dark:bg-gray-800/50 border border-gray-300 dark:border-gray-600 rounded-xl focus:ring-2 focus:ring-emerald-500 focus:border-emerald-500 dark:focus:ring-emerald-400 dark:text-white transition-colors" disabled={isUpdating} />
) : ( <>
setListId(e.target.value)} placeholder="e.g., 1234, want-to-read, status-1" className="w-full px-4 py-2 bg-gray-50 dark:bg-gray-800/50 border border-gray-300 dark:border-gray-600 rounded-xl focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500 dark:focus:ring-indigo-400 dark:text-white transition-colors" disabled={isUpdating} />
setApiToken(e.target.value)} placeholder="Paste your Hardcover token here..." className="w-full px-4 py-2 bg-gray-50 dark:bg-gray-800/50 border border-gray-300 dark:border-gray-600 rounded-xl focus:ring-2 focus:ring-indigo-500 focus:border-indigo-500 dark:focus:ring-indigo-400 dark:text-white transition-colors" disabled={isUpdating} />
)}
); }