diff --git a/apps/web/components/FeedSection.tsx b/apps/web/components/FeedSection.tsx index e05bdc4..1d081b1 100644 --- a/apps/web/components/FeedSection.tsx +++ b/apps/web/components/FeedSection.tsx @@ -6,6 +6,8 @@ import { listMedia, type ListSort } from "@/lib/queries"; import { toClientCard } from "@/lib/serialize"; import { getCurrentUser, canParticipate } from "@/lib/session"; import { PAGE_SIZE } from "@/lib/queries"; +import { pageCount } from "@/lib/pagination"; +import { notFound } from "next/navigation"; const TABS: { label: string; href: string; sort?: ListSort }[] = [ { label: "Newest", href: "/" }, @@ -21,6 +23,8 @@ export async function FeedSection({ page }: { page: number }) { page, userId: user?.id ?? null, }); + const totalPages = pageCount(total, PAGE_SIZE); + if (page > totalPages) notFound(); return ( <> diff --git a/apps/web/components/Pagination.tsx b/apps/web/components/Pagination.tsx index b49009f..fd3c84a 100644 --- a/apps/web/components/Pagination.tsx +++ b/apps/web/components/Pagination.tsx @@ -1,4 +1,5 @@ import Link from "next/link"; +import { pageCount } from "@/lib/pagination"; export function Pagination({ page, @@ -13,7 +14,7 @@ export function Pagination({ basePath: string; // e.g. "/page" or "/search" query?: string; // extra query string without leading ? }) { - const pages = Math.max(1, Math.ceil(total / pageSize)); + const pages = pageCount(total, pageSize); if (pages <= 1) return null; const mk = (p: number) => { if (basePath === "/page") return p <= 1 ? `/` : `/page/${p}`; diff --git a/apps/web/lib/pagination.test.ts b/apps/web/lib/pagination.test.ts index 77fa540..489ee3f 100644 --- a/apps/web/lib/pagination.test.ts +++ b/apps/web/lib/pagination.test.ts @@ -1,5 +1,5 @@ import { describe, expect, it } from "vitest"; -import { normalizePage } from "./pagination"; +import { normalizePage, pageCount } from "./pagination"; describe("normalizePage", () => { it("accepts positive numeric page values", () => { @@ -24,3 +24,14 @@ describe("normalizePage", () => { expect(normalizePage("-2")).toBe(1); }); }); + +describe("pageCount", () => { + it("keeps an empty feed on its first page", () => { + expect(pageCount(0, 24)).toBe(1); + }); + + it("rounds partial pages up", () => { + expect(pageCount(24, 24)).toBe(1); + expect(pageCount(25, 24)).toBe(2); + }); +}); diff --git a/apps/web/lib/pagination.ts b/apps/web/lib/pagination.ts index 6659170..8d79d5b 100644 --- a/apps/web/lib/pagination.ts +++ b/apps/web/lib/pagination.ts @@ -5,6 +5,10 @@ export function normalizePage(value: unknown, fallback = 1): number { return parsed >= 1 ? parsed : fallback; } +export function pageCount(total: number, pageSize: number): number { + return Math.max(1, Math.ceil(total / pageSize)); +} + export function parsePageInteger(value: unknown): number | null { if (typeof value === "number") { return Number.isSafeInteger(value) ? value : null;