"use client"; import type { NormalizedBook } from "@/lib/providers/types"; import { BookCover } from "@/components/ui/book-cover"; import { useState, useEffect, useRef } from "react"; import { useTranslate } from "@/hooks/useTranslate"; import { cn } from "@/lib/utils"; import { useBookOfflineStatus } from "@/hooks/useBookOfflineStatus"; import { formatDate } from "@/lib/utils"; import { ClientOfflineBookService } from "@/lib/services/client-offlinebook.service"; import { Progress } from "@/components/ui/progress"; import { FileText } from "lucide-react"; import { MarkAsReadButton } from "@/components/ui/mark-as-read-button"; import { MarkAsUnreadButton } from "@/components/ui/mark-as-unread-button"; import { BookOfflineButton } from "@/components/ui/book-offline-button"; interface BookListProps { books: NormalizedBook[]; onBookClick: (book: NormalizedBook) => void; isCompact?: boolean; onRefresh?: () => void; } interface BookListItemProps { book: NormalizedBook; onBookClick: (book: NormalizedBook) => void; onSuccess: (book: NormalizedBook, action: "read" | "unread") => void; isCompact?: boolean; } function BookListItem({ book, onBookClick, onSuccess, isCompact = false }: BookListItemProps) { const { t } = useTranslate(); const { isAccessible } = useBookOfflineStatus(book.id); const handleClick = () => { if (!isAccessible) return; onBookClick(book); }; const isRead = book.readProgress?.completed || false; const hasReadProgress = book.readProgress !== null; const currentPage = ClientOfflineBookService.getCurrentPage(book); const totalPages = book.pageCount; const progressPercentage = totalPages > 0 ? (currentPage / totalPages) * 100 : 0; const getStatusInfo = () => { if (!book.readProgress) { return { label: t("books.status.unread"), className: "bg-yellow-500/10 text-yellow-500", }; } if (book.readProgress.completed) { const readDate = book.readProgress.lastReadAt ? formatDate(book.readProgress.lastReadAt) : null; return { label: readDate ? t("books.status.readDate", { date: readDate }) : t("books.status.read"), className: "bg-green-500/10 text-green-500", }; } if (currentPage > 0) { return { label: t("books.status.progress", { current: currentPage, total: totalPages, }), className: "bg-blue-500/10 text-blue-500", }; } return { label: t("books.status.unread"), className: "bg-yellow-500/10 text-yellow-500", }; }; const statusInfo = getStatusInfo(); const title = book.title || (book.number ? t("navigation.volume", { number: book.number }) : ""); if (isCompact) { return (
{/* Couverture compacte */}
{/* Contenu compact */}
{/* Titre et statut */}

{title}

{statusInfo.label}
{/* Métadonnées minimales */}
{book.number && ( {t("navigation.volume", { number: book.number })} )}
{totalPages} {totalPages > 1 ? t("books.pages_plural") : t("books.pages")}
); } return (
{/* Couverture */}
{/* Contenu */}
{/* Titre et numéro */}

{title}

{book.number && (

{t("navigation.volume", { number: book.number })}

)}
{/* Badge de statut */} {statusInfo.label}
{/* Métadonnées */}
{/* Pages */}
{totalPages} {totalPages > 1 ? t("books.pages_plural") : t("books.pages")}
{/* Barre de progression */} {hasReadProgress && !isRead && currentPage > 0 && (

{Math.round(progressPercentage)}% {t("books.completed")}

)} {/* Actions */}
{!isRead && ( onSuccess(book, "read")} className="text-xs" /> )} {hasReadProgress && ( onSuccess(book, "unread")} className="text-xs" /> )}
); } export function BookList({ books, onBookClick, isCompact = false, onRefresh }: BookListProps) { const [localBooks, setLocalBooks] = useState(books); const { t } = useTranslate(); const previousBookIdsRef = useRef(books.map((b) => b.id).join(",")); useEffect(() => { // Ne réinitialiser que si les IDs des livres ont changé (nouvelle page, nouveau filtre, etc.) const newIds = books.map((b) => b.id).join(","); if (previousBookIdsRef.current !== newIds) { setLocalBooks(books); previousBookIdsRef.current = newIds; } }, [books]); if (!localBooks.length) { return (

{t("books.empty")}

); } const handleOnSuccess = (book: NormalizedBook, action: "read" | "unread") => { if (action === "read") { setLocalBooks( localBooks.map((previousBook) => previousBook.id === book.id ? { ...previousBook, readProgress: { completed: true, page: previousBook.pageCount, lastReadAt: new Date().toISOString(), }, } : previousBook ) ); } else if (action === "unread") { setLocalBooks( localBooks.map((previousBook) => previousBook.id === book.id ? { ...previousBook, readProgress: null, } : previousBook ) ); } // Rafraîchir les données après avoir marqué comme lu/non lu onRefresh?.(); }; return (
{localBooks.map((book) => ( ))}
); }