7.2 목록 페이징/정렬/검색(제목/태그/작성자/기간) o

This commit is contained in:
koreacomp5
2025-10-09 16:54:24 +09:00
parent 7342c9bea2
commit a15b62f785
4 changed files with 33 additions and 6 deletions

View File

@@ -38,6 +38,10 @@ const listQuerySchema = z.object({
boardId: z.string().optional(),
q: z.string().optional(),
sort: z.enum(["recent", "popular"]).default("recent").optional(),
tag: z.string().optional(), // Tag.slug
author: z.string().optional(), // User.nickname contains
start: z.coerce.date().optional(), // createdAt >= start
end: z.coerce.date().optional(), // createdAt <= end
});
export async function GET(req: Request) {
@@ -46,7 +50,7 @@ export async function GET(req: Request) {
if (!parsed.success) {
return NextResponse.json({ error: parsed.error.flatten() }, { status: 400 });
}
const { page, pageSize, boardId, q, sort = "recent" } = parsed.data;
const { page, pageSize, boardId, q, sort = "recent", tag, author, start, end } = parsed.data;
const where = {
NOT: { status: "deleted" as const },
...(boardId ? { boardId } : {}),
@@ -58,6 +62,24 @@ export async function GET(req: Request) {
],
}
: {}),
...(tag
? {
postTags: { some: { tag: { slug: tag } } },
}
: {}),
...(author
? {
author: { nickname: { contains: author } },
}
: {}),
...(start || end
? {
createdAt: {
...(start ? { gte: start } : {}),
...(end ? { lte: end } : {}),
},
}
: {}),
} as const;
const [total, items] = await Promise.all([

View File

@@ -20,7 +20,7 @@ type Resp = {
const fetcher = (url: string) => fetch(url).then((r) => r.json());
export function PostList({ boardId, sort = "recent", q }: { boardId?: string; sort?: "recent" | "popular"; q?: string }) {
export function PostList({ boardId, sort = "recent", q, tag, author, start, end }: { boardId?: string; sort?: "recent" | "popular"; q?: string; tag?: string; author?: string; start?: string; end?: string }) {
const pageSize = 10;
const getKey = (index: number, prev: Resp | null) => {
if (prev && prev.items.length === 0) return null;
@@ -28,6 +28,10 @@ export function PostList({ boardId, sort = "recent", q }: { boardId?: string; so
const sp = new URLSearchParams({ page: String(page), pageSize: String(pageSize), sort });
if (boardId) sp.set("boardId", boardId);
if (q) sp.set("q", q);
if (tag) sp.set("tag", tag);
if (author) sp.set("author", author);
if (start) sp.set("start", start);
if (end) sp.set("end", end);
return `/api/posts?${sp.toString()}`;
};
const { data, size, setSize, isLoading } = useSWRInfinite<Resp>(getKey, fetcher);

View File

@@ -1,12 +1,13 @@
import { PostList } from "@/app/components/PostList";
export default function SearchPage({ searchParams }: { searchParams?: { q?: string; sort?: "recent" | "popular" } }) {
export default function SearchPage({ searchParams }: { searchParams?: { q?: string; sort?: "recent" | "popular"; tag?: string; author?: string; start?: string; end?: string } }) {
const q = searchParams?.q ?? "";
const sort = searchParams?.sort ?? "recent";
const { tag = "", author = "", start = "", end = "" } = searchParams ?? {};
return (
<div>
<h2 style={{ marginBottom: 12 }}>: {q || "전체"}</h2>
<PostList q={q} sort={sort} />
<h2 style={{ marginBottom: 12 }}>: {q || tag || author || (start && end ? `${start}~${end}` : "전체")}</h2>
<PostList q={q} sort={sort} tag={tag} author={author} start={start} end={end} />
</div>
);
}