From 4139d8a059bf91b3ddd28e167db99494526b12a9 Mon Sep 17 00:00:00 2001 From: Julien Froidefond Date: Thu, 16 Oct 2025 13:25:51 +0200 Subject: [PATCH] refactor: streamline LibraryPage component by integrating ClientLibraryPage for improved structure and error handling --- .../[libraryId]/ClientLibraryPage.tsx | 83 +++++++++++++++++++ src/app/libraries/[libraryId]/page.tsx | 68 +++++++-------- src/components/home/MediaRow.tsx | 14 +++- .../library/PaginatedSeriesGrid.tsx | 15 ---- src/components/series/BookGrid.tsx | 5 +- src/components/series/SeriesHeader.tsx | 5 +- src/components/ui/book-cover.tsx | 19 +++-- src/i18n/messages/en/common.json | 10 +++ src/i18n/messages/fr/common.json | 10 +++ 9 files changed, 167 insertions(+), 62 deletions(-) create mode 100644 src/app/libraries/[libraryId]/ClientLibraryPage.tsx diff --git a/src/app/libraries/[libraryId]/ClientLibraryPage.tsx b/src/app/libraries/[libraryId]/ClientLibraryPage.tsx new file mode 100644 index 0000000..55f8db7 --- /dev/null +++ b/src/app/libraries/[libraryId]/ClientLibraryPage.tsx @@ -0,0 +1,83 @@ +"use client"; + +import { PaginatedSeriesGrid } from "@/components/library/PaginatedSeriesGrid"; +import { RefreshButton } from "@/components/library/RefreshButton"; +import { ErrorMessage } from "@/components/ui/ErrorMessage"; +import { useTranslate } from "@/hooks/useTranslate"; +import type { LibraryResponse } from "@/types/library"; +import type { KomgaSeries, KomgaLibrary } from "@/types/komga"; +import type { UserPreferences } from "@/types/preferences"; + +interface ClientLibraryPageProps { + library: KomgaLibrary | null; + series: LibraryResponse | null; + currentPage: number; + libraryId: string; + refreshLibrary: (libraryId: string) => Promise<{ success: boolean; error?: string }>; + preferences: UserPreferences; + unreadOnly: boolean; + errorCode?: string; +} + +export function ClientLibraryPage({ + library, + series, + currentPage, + libraryId, + refreshLibrary, + preferences, + unreadOnly, + errorCode, +}: ClientLibraryPageProps) { + const { t } = useTranslate(); + + if (errorCode) { + return ( +
+
+

+ {library?.name || t("series.empty")} +

+ +
+ +
+ ); + } + + if (!library || !series) { + return ( +
+ +
+ ); + } + + return ( +
+
+

{library.name}

+
+ {series.totalElements > 0 && ( +

+ {t("series.display.showing", { + start: ((currentPage - 1) * (preferences.displayMode?.itemsPerPage || 20)) + 1, + end: Math.min(currentPage * (preferences.displayMode?.itemsPerPage || 20), series.totalElements), + total: series.totalElements, + })} +

+ )} + +
+
+ +
+ ); +} diff --git a/src/app/libraries/[libraryId]/page.tsx b/src/app/libraries/[libraryId]/page.tsx index a95e55d..2fd254d 100644 --- a/src/app/libraries/[libraryId]/page.tsx +++ b/src/app/libraries/[libraryId]/page.tsx @@ -1,15 +1,13 @@ -import { PaginatedSeriesGrid } from "@/components/library/PaginatedSeriesGrid"; import { LibraryService } from "@/lib/services/library.service"; import { PreferencesService } from "@/lib/services/preferences.service"; import { revalidatePath } from "next/cache"; -import { RefreshButton } from "@/components/library/RefreshButton"; import { withPageTiming } from "@/lib/hoc/withPageTiming"; -import { ErrorMessage } from "@/components/ui/ErrorMessage"; import type { LibraryResponse } from "@/types/library"; import type { KomgaSeries, KomgaLibrary } from "@/types/komga"; import type { UserPreferences } from "@/types/preferences"; import { ERROR_CODES } from "@/constants/errorCodes"; import { AppError } from "@/utils/errors"; +import { ClientLibraryPage } from "./ClientLibraryPage"; interface PageProps { params: { libraryId: string }; @@ -27,8 +25,8 @@ async function refreshLibrary(libraryId: string) { revalidatePath(`/libraries/${libraryId}`); return { success: true }; } catch (error) { - console.error("Erreur lors du rafraîchissement:", error); - return { success: false, error: "Erreur lors du rafraîchissement de la bibliothèque" }; + console.error("Error during refresh:", error); + return { success: false, error: "Error refreshing library" }; } } @@ -75,44 +73,42 @@ async function LibraryPage({ params, searchParams }: PageProps) { await getLibrarySeries(libraryId, currentPage, unreadOnly, search, pageSize); return ( -
-
-

{library.name}

-
- {series.totalElements > 0 && ( -

- {series.totalElements} série{series.totalElements > 1 ? "s" : ""} -

- )} - -
-
- -
+ ); } catch (error) { if (error instanceof AppError) { return ( -
-
-

Séries

- -
- -
+ ); } return ( -
- -
+ ); } } diff --git a/src/components/home/MediaRow.tsx b/src/components/home/MediaRow.tsx index f5bed16..b3e3d68 100644 --- a/src/components/home/MediaRow.tsx +++ b/src/components/home/MediaRow.tsx @@ -6,6 +6,7 @@ import { useRouter } from "next/navigation"; import type { KomgaBook, KomgaSeries } from "@/types/komga"; import { BookCover } from "../ui/book-cover"; import { SeriesCover } from "../ui/series-cover"; +import { useTranslate } from "@/hooks/useTranslate"; interface BaseItem { id: string; @@ -43,6 +44,7 @@ export function MediaRow({ title, items, icon }: MediaRowProps) { const [showLeftArrow, setShowLeftArrow] = useState(false); const [showRightArrow, setShowRightArrow] = useState(true); const router = useRouter(); + const { t } = useTranslate(); const onItemClick = (item: OptimizedSeries | OptimizedBook) => { const path = "booksCount" in item ? `/series/${item.id}` : `/books/${item.id}`; @@ -78,7 +80,7 @@ export function MediaRow({ title, items, icon }: MediaRowProps) { @@ -100,7 +102,7 @@ export function MediaRow({ title, items, icon }: MediaRowProps) { @@ -116,10 +118,14 @@ interface MediaCardProps { } function MediaCard({ item, onClick }: MediaCardProps) { + const { t } = useTranslate(); const isSeries = "booksCount" in item; const title = isSeries ? item.metadata.title - : item.metadata.title || `Tome ${item.metadata.number}`; + : item.metadata.title || + (item.metadata.number + ? t("navigation.volume", { number: item.metadata.number }) + : ""); return (

{title}

- {item.booksCount} tome{item.booksCount > 1 ? "s" : ""} + {t("series.books", { count: item.booksCount })}

diff --git a/src/components/library/PaginatedSeriesGrid.tsx b/src/components/library/PaginatedSeriesGrid.tsx index 10050f4..159a601 100644 --- a/src/components/library/PaginatedSeriesGrid.tsx +++ b/src/components/library/PaginatedSeriesGrid.tsx @@ -105,24 +105,9 @@ export function PaginatedSeriesGrid({ }); }; - // Calculate start and end indices for display - const startIndex = (currentPage - 1) * itemsPerPage + 1; - const endIndex = Math.min(currentPage * itemsPerPage, totalElements); - - const getShowingText = () => { - if (!totalElements) return t("series.empty"); - - return t("series.display.showing", { - start: startIndex, - end: endIndex, - total: totalElements, - }); - }; - return (
-

{getShowingText()}

diff --git a/src/components/series/BookGrid.tsx b/src/components/series/BookGrid.tsx index 70e0c6c..a3d5148 100644 --- a/src/components/series/BookGrid.tsx +++ b/src/components/series/BookGrid.tsx @@ -85,7 +85,10 @@ export function BookGrid({ books, onBookClick, isCompact = false }: BookGridProp handleOnSuccess(book, action)} /> diff --git a/src/components/series/SeriesHeader.tsx b/src/components/series/SeriesHeader.tsx index 0d558b4..f22dfc7 100644 --- a/src/components/series/SeriesHeader.tsx +++ b/src/components/series/SeriesHeader.tsx @@ -158,7 +158,10 @@ export const SeriesHeader = ({ series, refreshSeries }: SeriesHeaderProps) => { {statusInfo.label} - {t("series.header.books", { count: series.booksCount })} + {series.booksCount === 1 + ? t("series.header.books", { count: series.booksCount }) + : t("series.header.books_plural", { count: series.booksCount }) + }