import { useEffect, useState, type FormEvent } from 'react' import { Link, useNavigate, useParams } from 'react-router' import { api, ApiError, errorMessage, type Book } from '../api' import { card, inputClass, labelText, primaryButton, secondaryButton } from '../ui' import { useGenres } from './useGenres' type Fields = { title: string; author: string; genre_id: string; total_pages: string; current_page: string } type FormError = { message: string; field?: string } const EMPTY: Fields = { title: '', author: '', genre_id: '', total_pages: '', current_page: '0' } export function BookForm() { const { id } = useParams() const editing = id !== undefined const navigate = useNavigate() const { genres, error: genresError } = useGenres() const [fields, setFields] = useState(EMPTY) const [loading, setLoading] = useState(editing) const [loadError, setLoadError] = useState(null) const [error, setError] = useState(null) const [busy, setBusy] = useState(false) const [attempt, setAttempt] = useState(0) useEffect(() => { if (!editing) return let cancelled = false setLoadError(null) setLoading(true) api('GET', `/books/${id}`).then( (book) => { if (cancelled) return setFields({ title: book.title, author: book.author, genre_id: String(book.genre.id), total_pages: String(book.total_pages), current_page: String(book.current_page), }) setLoading(false) }, (err) => { if (cancelled) return setLoadError(errorMessage(err)) setLoading(false) }, ) return () => { cancelled = true } }, [editing, id, attempt]) function set(name: keyof Fields) { return (event: { target: { value: string } }) => setFields((prev) => ({ ...prev, [name]: event.target.value })) } function invalid(name: keyof Fields) { return error?.field === name ? { 'aria-invalid': true, 'aria-describedby': 'form-error' } : {} } async function submit(event: FormEvent) { event.preventDefault() setError(null) setBusy(true) const payload = { title: fields.title, author: fields.author, genre_id: Number(fields.genre_id), total_pages: Number(fields.total_pages), current_page: Number(fields.current_page), } try { const saved = editing ? await api('PATCH', `/books/${id}`, payload) : await api('POST', '/books', payload) navigate(`/books/${saved.id}`) } catch (err) { setError({ message: errorMessage(err), field: err instanceof ApiError ? err.field : undefined }) setBusy(false) } } if (loadError) { return (

{loadError}

← Back to library
) } if (loading) return

Loading…

return (

{editing ? 'Edit book' : 'Add a book'}

{genresError &&

{`Could not load genres: ${genresError}`}

}
{error && ( )}
Cancel
) }