import { fetchLibraries, getBookCoverUrl, BookDto, apiFetch, ReadingStatus } from "../../../lib/api"; import { BookPreview } from "../../components/BookPreview"; import { ConvertButton } from "../../components/ConvertButton"; import { MarkBookReadButton } from "../../components/MarkBookReadButton"; import { EditBookForm } from "../../components/EditBookForm"; import { SafeHtml } from "../../components/SafeHtml"; import Image from "next/image"; import Link from "next/link"; import { notFound } from "next/navigation"; export const dynamic = "force-dynamic"; const readingStatusConfig: Record = { unread: { label: "Non lu", className: "bg-muted/60 text-muted-foreground border border-border" }, reading: { label: "En cours", className: "bg-amber-500/15 text-amber-600 dark:text-amber-400 border border-amber-500/30" }, read: { label: "Lu", className: "bg-green-500/15 text-green-600 dark:text-green-400 border border-green-500/30" }, }; async function fetchBook(bookId: string): Promise { try { return await apiFetch(`/books/${bookId}`); } catch { return null; } } export default async function BookDetailPage({ params }: { params: Promise<{ id: string }>; }) { const { id } = await params; const [book, libraries] = await Promise.all([ fetchBook(id), fetchLibraries().catch(() => [] as { id: string; name: string }[]) ]); if (!book) { notFound(); } const library = libraries.find(l => l.id === book.library_id); const formatBadge = (book.format ?? book.kind).toUpperCase(); const formatColor = formatBadge === "CBZ" ? "bg-success/10 text-success border-success/30" : formatBadge === "CBR" ? "bg-warning/10 text-warning border-warning/30" : formatBadge === "PDF" ? "bg-destructive/10 text-destructive border-destructive/30" : "bg-muted/50 text-muted-foreground border-border"; const { label: statusLabel, className: statusClassName } = readingStatusConfig[book.reading_status]; return (
{/* Breadcrumb */}
Libraries / {library && ( <> {library.name} / )} {book.series && ( <> {book.series} / )} {book.title}
{/* Hero */}
{/* Cover */}
{`Cover
{/* Info */}

{book.title}

{book.author && (

{book.author}

)}
{/* Series + Volume link */} {book.series && (
{book.series} {book.volume != null && ( Vol. {book.volume} )}
)} {/* Reading status + actions */}
{statusLabel} {book.reading_status === "reading" && book.reading_current_page != null && ` · p. ${book.reading_current_page}`} {book.reading_last_read_at && ( {new Date(book.reading_last_read_at).toLocaleDateString()} )} {book.file_format === "cbr" && }
{/* Metadata pills */}
{formatBadge} {book.page_count && ( {book.page_count} pages )} {book.language && ( {book.language.toUpperCase()} )} {book.isbn && ( ISBN {book.isbn} )} {book.publish_date && ( {book.publish_date} )}
{/* Description */} {book.summary && ( )}
{/* Technical info (collapsible) */}
Informations techniques
{book.file_path && (
Fichier {book.file_path}
)} {book.file_format && (
Format fichier {book.file_format.toUpperCase()}
)} {book.file_parse_status && (
Parsing {book.file_parse_status}
)}
Book ID {book.id}
Library ID {book.library_id}
{book.updated_at && (
Mis à jour {new Date(book.updated_at).toLocaleString()}
)}
{/* Book Preview */} {book.page_count && book.page_count > 0 && ( )}
); }