Files
2026-DEV-BUT3/src/pages/SearchPage.jsx
T
2026-05-03 13:10:19 +02:00

139 lines
4.1 KiB
React
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import axios from 'axios'
import { useState } from 'react'
import { useBooks } from '../context/BooksContext.jsx'
const OPEN_LIBRARY_SEARCH = 'https://openlibrary.org/search.json'
function docToBookPayload(doc) {
return {
title: doc.title || 'Sans titre',
author: Array.isArray(doc.author_name)
? doc.author_name[0]
: 'Auteur inconnu',
year:
typeof doc.first_publish_year === 'number'
? doc.first_publish_year
: new Date().getFullYear(),
genre: Array.isArray(doc.subject) ? doc.subject[0] : '',
price: 10,
read: false,
}
}
function resultKey(doc, index) {
return doc.key || doc.cover_edition_key || `${doc.title || 'work'}-${index}`
}
export default function SearchPage() {
const { postBook } = useBooks()
const [q, setQ] = useState('')
const [loading, setLoading] = useState(false)
const [error, setError] = useState(null)
const [docs, setDocs] = useState([])
const [addedKeys, setAddedKeys] = useState(() => new Set())
const [lastQuery, setLastQuery] = useState('')
async function handleSearch(e) {
e.preventDefault()
const term = q.trim()
if (!term) return
setLoading(true)
setError(null)
setDocs([])
setAddedKeys(() => new Set())
setLastQuery(term)
try {
const { data } = await axios.get(OPEN_LIBRARY_SEARCH, {
params: { q: term, limit: 15 },
timeout: 15000,
})
setDocs(Array.isArray(data.docs) ? data.docs : [])
} catch (err) {
setError(
err.response?.data?.error ||
err.message ||
'Impossible de contacter Open Library.',
)
} finally {
setLoading(false)
}
}
function handleAdd(doc, index) {
postBook(docToBookPayload(doc))
const k = resultKey(doc, index)
setAddedKeys((prev) => new Set(prev).add(k))
}
return (
<div className="search-page">
<h2 className="search-page-title">Recherche Open Library</h2>
<p className="search-page-lead">
Interroge lAPI publique Open Library avec Axios, puis ajoute un
ouvrage à ton catalogue local.
</p>
<form className="search-form" onSubmit={handleSearch}>
<input
type="search"
className="search search-wide"
placeholder="Titre, auteur, sujet…"
value={q}
onChange={(e) => setQ(e.target.value)}
aria-label="Requête Open Library"
/>
<button type="submit" className="btn primary" disabled={loading}>
{loading ? 'Recherche…' : 'Rechercher'}
</button>
</form>
{error ? (
<p className="search-error" role="alert">
{error}
</p>
) : null}
{!loading && docs.length === 0 && !error && !lastQuery ? (
<p className="search-hint">Saisis un mot-clé et lance la recherche.</p>
) : null}
{!loading && docs.length === 0 && !error && lastQuery ? (
<p className="search-hint">Aucun résultat pour « {lastQuery} ».</p>
) : null}
{docs.length > 0 ? (
<ul className="ol-results">
{docs.map((doc, i) => {
const key = resultKey(doc, i)
const year =
typeof doc.first_publish_year === 'number'
? doc.first_publish_year
: '—'
const authors = Array.isArray(doc.author_name)
? doc.author_name.slice(0, 2).join(', ')
: '—'
const justAdded = addedKeys.has(key)
return (
<li key={key} className="ol-result-card">
<h3 className="ol-result-title">
{doc.title || 'Sans titre'}
</h3>
<p className="ol-result-meta">
{authors} · {year}
</p>
<button
type="button"
className="btn small primary"
onClick={() => handleAdd(doc, i)}
disabled={justAdded}
>
{justAdded ? 'Enregistré' : 'Enregistrer (POST /api/books)'}
</button>
</li>
)
})}
</ul>
) : null}
</div>
)
}