import { fetchAllSeries, fetchLibraries, fetchSeriesStatuses, LibraryDto, SeriesDto, SeriesPageDto, getBookCoverUrl } from "../../lib/api"; import { getServerTranslations } from "../../lib/i18n/server"; import { MarkSeriesReadButton } from "../components/MarkSeriesReadButton"; import { LiveSearchForm } from "../components/LiveSearchForm"; import { Card, CardContent, OffsetPagination } from "../components/ui"; import Image from "next/image"; import Link from "next/link"; import { ProviderIcon } from "../components/ProviderIcon"; export const dynamic = "force-dynamic"; export default async function SeriesPage({ searchParams, }: { searchParams: Promise<{ [key: string]: string | string[] | undefined }>; }) { const { t } = await getServerTranslations(); 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 seriesStatus = typeof searchParamsAwaited.series_status === "string" ? searchParamsAwaited.series_status : undefined; const hasMissing = searchParamsAwaited.has_missing === "true"; const metadataProvider = typeof searchParamsAwaited.metadata_provider === "string" ? searchParamsAwaited.metadata_provider : undefined; const page = typeof searchParamsAwaited.page === "string" ? parseInt(searchParamsAwaited.page) : 1; const limit = typeof searchParamsAwaited.limit === "string" ? parseInt(searchParamsAwaited.limit) : 20; const [libraries, seriesPage, dbStatuses] = await Promise.all([ fetchLibraries().catch(() => [] as LibraryDto[]), fetchAllSeries(libraryId, searchQuery || undefined, readingStatus, page, limit, sort, seriesStatus, hasMissing, metadataProvider).catch( () => ({ items: [] as SeriesDto[], total: 0, page: 1, limit }) as SeriesPageDto ), fetchSeriesStatuses().catch(() => [] as string[]), ]); const series = seriesPage.items; const totalPages = Math.ceil(seriesPage.total / limit); const sortOptions = [ { value: "", label: t("books.sortTitle") }, { value: "latest", label: t("books.sortLatest") }, ]; const hasFilters = searchQuery || libraryId || readingStatus || sort || seriesStatus || hasMissing || metadataProvider; const libraryOptions = [ { value: "", label: t("books.allLibraries") }, ...libraries.map((lib) => ({ value: lib.id, label: lib.name })), ]; const statusOptions = [ { value: "", label: t("common.all") }, { value: "unread", label: t("status.unread") }, { value: "reading", label: t("status.reading") }, { value: "read", label: t("status.read") }, ]; const KNOWN_STATUSES: Record = { ongoing: t("seriesStatus.ongoing"), ended: t("seriesStatus.ended"), hiatus: t("seriesStatus.hiatus"), cancelled: t("seriesStatus.cancelled"), upcoming: t("seriesStatus.upcoming"), }; const seriesStatusOptions = [ { value: "", label: t("seriesStatus.allStatuses") }, ...dbStatuses.map((s) => ({ value: s, label: KNOWN_STATUSES[s] || s })), ]; const missingOptions = [ { value: "", label: t("common.all") }, { value: "true", label: t("series.missingBooks") }, ]; const metadataOptions = [ { value: "", label: t("series.metadataAll") }, { value: "linked", label: t("series.metadataLinked") }, { value: "unlinked", label: t("series.metadataUnlinked") }, { value: "google_books", label: "Google Books" }, { value: "open_library", label: "Open Library" }, { value: "comicvine", label: "ComicVine" }, { value: "anilist", label: "AniList" }, { value: "bedetheque", label: "Bédéthèque" }, ]; return ( <>

{t("series.title")}

{/* Results count */}

{seriesPage.total} {t("series.title").toLowerCase()} {searchQuery && <> {t("series.matchingQuery")} "{searchQuery}"}

{/* Series Grid */} {series.length > 0 ? ( <>
{series.map((s) => (
= s.book_count ? "opacity-50" : "" }`} >
{t("books.coverOf",

{s.name === "unclassified" ? t("books.unclassified") : s.name}

{t("series.readCount", { read: String(s.books_read_count), total: String(s.book_count), plural: s.book_count !== 1 ? "s" : "" })}

{s.series_status && ( {KNOWN_STATUSES[s.series_status] || s.series_status} )} {s.missing_count != null && s.missing_count > 0 && ( {t("series.missingCount", { count: String(s.missing_count), plural: s.missing_count > 1 ? "s" : "" })} )} {s.metadata_provider && ( )}
))}
) : (

{hasFilters ? t("series.noResults") : t("series.noSeries")}

)} ); }