import { fetchBooks, searchBooks, fetchLibraries, BookDto, LibraryDto, SeriesHitDto, getBookCoverUrl } from "../../lib/api"; import { BooksGrid, EmptyState } from "../components/BookCard"; import { LiveSearchForm } from "../components/LiveSearchForm"; import { Card, CardContent, OffsetPagination } from "../components/ui"; import Link from "next/link"; import Image from "next/image"; export const dynamic = "force-dynamic"; export default async function BooksPage({ searchParams }: { searchParams: Promise<{ [key: string]: string | string[] | undefined }>; }) { const searchParamsAwaited = await searchParams; const libraryId = typeof searchParamsAwaited.library === "string" ? searchParamsAwaited.library : undefined; const searchQuery = typeof searchParamsAwaited.q === "string" ? searchParamsAwaited.q : ""; const readingStatus = typeof searchParamsAwaited.status === "string" ? searchParamsAwaited.status : undefined; const sort = typeof searchParamsAwaited.sort === "string" ? searchParamsAwaited.sort : undefined; const page = typeof searchParamsAwaited.page === "string" ? parseInt(searchParamsAwaited.page) : 1; const limit = typeof searchParamsAwaited.limit === "string" ? parseInt(searchParamsAwaited.limit) : 20; const [libraries] = await Promise.all([ fetchLibraries().catch(() => [] as LibraryDto[]) ]); let books: BookDto[] = []; let total = 0; let searchResults: BookDto[] | null = null; let seriesHits: SeriesHitDto[] = []; let totalHits: number | null = null; if (searchQuery) { const searchResponse = await searchBooks(searchQuery, libraryId, limit).catch(() => null); if (searchResponse) { seriesHits = searchResponse.series_hits ?? []; searchResults = searchResponse.hits.map(hit => ({ id: hit.id, library_id: hit.library_id, kind: hit.kind, title: hit.title, author: hit.author, series: hit.series, volume: hit.volume, language: hit.language, page_count: null, format: null, file_path: null, file_format: null, file_parse_status: null, updated_at: "", reading_status: "unread" as const, reading_current_page: null, reading_last_read_at: null, })); totalHits = searchResponse.estimated_total_hits; } } else { const booksPage = await fetchBooks(libraryId, undefined, page, limit, readingStatus, sort).catch(() => ({ items: [] as BookDto[], total: 0, page: 1, limit, })); books = booksPage.items; total = booksPage.total; } const displayBooks = (searchResults || books).map(book => ({ ...book, coverUrl: getBookCoverUrl(book.id) })); const totalPages = Math.ceil(total / limit); const libraryOptions = [ { value: "", label: "All libraries" }, ...libraries.map((lib) => ({ value: lib.id, label: lib.name })), ]; const statusOptions = [ { value: "", label: "All" }, { value: "unread", label: "Unread" }, { value: "reading", label: "In progress" }, { value: "read", label: "Read" }, ]; const sortOptions = [ { value: "", label: "Title" }, { value: "latest", label: "Latest added" }, ]; const hasFilters = searchQuery || libraryId || readingStatus || sort; return ( <>

Books

{/* Résultats */} {searchQuery && totalHits !== null ? (

Found {totalHits} result{totalHits !== 1 ? 's' : ''} for "{searchQuery}"

) : !searchQuery && (

{total} book{total !== 1 ? 's' : ''}

)} {/* Séries matchantes */} {seriesHits.length > 0 && (

Series

{seriesHits.map((s) => (
{`Cover

{s.name === "unclassified" ? "Unclassified" : s.name}

{s.book_count} book{s.book_count !== 1 ? 's' : ''}

))}
)} {/* Grille de livres */} {displayBooks.length > 0 ? ( <> {searchQuery &&

Books

} {!searchQuery && ( )} ) : ( )} ); }