import Link from "next/link" import { ChevronLeft } from "lucide-react" import { NovelCard } from "@/components/novel-card" import { notFound } from "next/navigation" import { readerApiFetch, readerApiFetchNullable } from "@/lib/server-api" export const dynamic = "force-dynamic" type GenreItem = { id: string name: string slug: string description: string | null } type BrowseNovel = { id: string slug: string title: string authorName: string coverColor: string | null coverUrl: string | null rating: number views: number totalChapters: number status: string seriesId?: string | null } type BrowseResponse = { items: BrowseNovel[] } function collapseSeriesRows(rows: T[]): T[] { const pickedSeries = new Set() const output: T[] = [] for (const row of rows) { if (!row.seriesId) { output.push(row) continue } if (pickedSeries.has(row.seriesId)) continue pickedSeries.add(row.seriesId) output.push(row) } return output } export default async function GenreDetailPage({ params }: { params: Promise<{ slug: string }> }) { const { slug } = await params const genres = await readerApiFetch("/api/genres") const genre = genres.find((item) => item.slug === slug) || null if (!genre) { notFound() } const browse = await readerApiFetch(`/api/novels/browse?genre=${encodeURIComponent(slug)}&sort=latest&page=1&limit=80`) const allNovels = collapseSeriesRows(browse.items).slice(0, 20) // Basic layout without sort for purely server side representation without search params. Optional searchParams can be added later if needed. return (
Thể Loại

{genre.name}

{genre.description}

{allNovels.length} truyện

{/* Spacer for symmetry if we add sort later */}
{allNovels.length === 0 ? (

Chưa có truyện nào

Thể loại này chưa có truyện, hãy quay lại sau.

) : (
{allNovels.map((novel) => ( ))}
)}
) }