// Server component instead of client component import Link from "next/link" import { Search } from "lucide-react" import { Input } from "@/components/ui/input" import { NovelCard } from "@/components/novel-card" import { prisma } from "@/lib/prisma" export const dynamic = "force-dynamic" const PAGE_SIZE = 20 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 SearchPage({ searchParams, }: { searchParams: Promise<{ [key: string]: string | undefined }> }) { const resolvedParams = await searchParams const q = resolvedParams.q || "" const sortBy = resolvedParams.sort || "latest" const genreFilter = resolvedParams.genreFilter || "all" const statusFilter = resolvedParams.statusFilter || "all" const requestedPage = Math.max(1, Number(resolvedParams.page || "1") || 1) // Build where clause let where: any = {} if (q) { where.OR = [ { title: { contains: q, mode: "insensitive" } }, { authorName: { contains: q, mode: "insensitive" } }, { originalAuthorName: { contains: q, mode: "insensitive" } }, { series: { name: { contains: q, mode: "insensitive" } } }, ] } if (genreFilter !== "all") { where.genres = { some: { genre: { slug: genreFilter } } } } if (statusFilter !== "all") { where.status = statusFilter } // Build order clause let orderBy: any = {} switch (sortBy) { case "popular": orderBy = { views: "desc" } break case "rating": orderBy = { rating: "desc" } break case "name": orderBy = { title: "asc" } break case "latest": default: orderBy = { updatedAt: "desc" } } let filteredNovels: any[] = [] let totalResults = 0 let totalPages = 1 let currentPage = requestedPage if (q) { totalResults = await prisma.novel.count({ where }) totalPages = Math.max(1, Math.ceil(totalResults / PAGE_SIZE)) currentPage = Math.min(currentPage, totalPages) filteredNovels = await prisma.novel.findMany({ where, orderBy, include: { series: { select: { id: true, name: true, slug: true, }, }, }, skip: (currentPage - 1) * PAGE_SIZE, take: PAGE_SIZE, }) } else { const filteredNovelsRaw = await prisma.novel.findMany({ where, orderBy, include: { series: { select: { id: true, name: true, slug: true, }, }, }, take: 500, }) const collapsed = collapseSeriesRows(filteredNovelsRaw) totalResults = collapsed.length totalPages = Math.max(1, Math.ceil(totalResults / PAGE_SIZE)) currentPage = Math.min(currentPage, totalPages) filteredNovels = collapsed.slice((currentPage - 1) * PAGE_SIZE, currentPage * PAGE_SIZE) } const genres = await prisma.genre.findMany({ orderBy: { name: "asc" } }) const pageRangeStart = Math.max(1, currentPage - 2) const pageRangeEnd = Math.min(totalPages, currentPage + 2) const pageNumbers = Array.from( { length: pageRangeEnd - pageRangeStart + 1 }, (_, index) => pageRangeStart + index ) const buildPageHref = (page: number) => { const params = new URLSearchParams() if (q) params.set("q", q) if (sortBy !== "latest") params.set("sort", sortBy) if (genreFilter !== "all") params.set("genreFilter", genreFilter) if (statusFilter !== "all") params.set("statusFilter", statusFilter) params.set("page", String(page)) return `/tim-kiem?${params.toString()}` } return (

Tìm Kiếm Truyện

{/* Search and Filters - This requires a client component wrapper ideally, but for now we can rely on standard form submissions to update searchParams */}
{/* Results */}

{totalResults} kết quả {totalResults > 0 && `(Trang ${currentPage}/${totalPages})`}

{filteredNovels.length === 0 ? (

Không tìm thấy truyện

Thử tìm kiếm với từ khóa khác hoặc thay đổi bộ lọc.

) : (
{filteredNovels.map((novel) => ( ))}
)} {totalPages > 1 && (
Trước {pageNumbers.map((page) => ( {page} ))} = totalPages ? "pointer-events-none opacity-50" : "hover:bg-muted"}`} > Sau
)}
) }