feat(web): bibliothèque et lecteur — grilles de livres bornées à 5 colonnes (max-width calc sur .book-grid et .home-book-grid), retrait du bandeau « API absente ou incomplete » de l'accueil, et véritables pages d'erreur « Livre introuvable » sur fiche et lecteur (suppression de getApiFallback, retour à l'accueil + réessayer — évolution #46)

This commit is contained in:
Git Agent
2026-08-28 23:29:03 +02:00
parent 644a4b0183
commit c2cdb07f9a
6 changed files with 106 additions and 34 deletions

View File

@ -1,6 +1,6 @@
import { Component, useCallback, useEffect, useMemo, useState, type ErrorInfo, type ReactNode } from "react";
import type { BookDto } from "@readabook/shared";
import { api, getApiFallback } from "../api/client";
import { api } from "../api/client";
import { CbzReader } from "../reader/CbzReader";
import { EpubReader } from "../reader/EpubReader";
import { pageLocator, parseCbrPageLocator, parseCbzPageLocator, parsePdfPageLocator, pdfPagePercent } from "../reader/locators";
@ -11,6 +11,7 @@ import { majorityVisiblePage, type ReaderMode } from "../reader/readerScroll";
import { useReaderPreferences } from "../reader/useReaderPreferences";
import { useReaderProgress } from "../reader/useReaderProgress";
import { navigate } from "../router";
import { EmptyState, LoadingState, Panel } from "../components/ui";
const idleControls: ReaderControls = {
canPrevious: false,
@ -74,10 +75,9 @@ export function ReaderPage({ bookId }: { bookId: number }) {
setError(undefined);
try {
setBook(await api.book(bookId));
} catch (loadError) {
const fallback = getApiFallback<BookDto>(loadError);
setBook(fallback ?? null);
setError(fallback ? "Lecteur ouvert en mode secours." : "Ouvrage indisponible.");
} catch {
setBook(null);
setError("Ce livre n'existe pas dans le catalogue.");
} finally {
setLoading(false);
}
@ -206,6 +206,26 @@ export function ReaderPage({ bookId }: { bookId: number }) {
[changeMode, mode, supportsMode]
);
if (loading && !book) return <LoadingState />;
if (!book) {
return (
<section className="reader-missing-page" role="alert">
<Panel>
<EmptyState title="Livre introuvable" detail={error ?? "Le serveur n'a pas renvoye cet ouvrage."} />
<div className="reader-error-actions">
<button className="ghost-button" onClick={() => navigate("/home")}>
Retour à l'accueil
</button>
<button className="ghost-button" onClick={() => void loadBook()}>
Réessayer
</button>
</div>
</Panel>
</section>
);
}
return (
<ReaderShell
title={book?.title ?? "Ouverture du lecteur"}
@ -251,14 +271,7 @@ export function ReaderPage({ bookId }: { bookId: number }) {
</div>
)}
>
{!book ? (
<div className="reader-fallback">
<span>{error ?? "Chargement du livre."}</span>
<button className="ghost-button" onClick={() => void loadBook()}>
Reessayer
</button>
</div>
) : book.format === "pdf" ? (
{book.format === "pdf" ? (
<PdfReader
url={fileUrl}
page={page}