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(), boardId: z.string().optional(),
q: z.string().optional(), q: z.string().optional(),
sort: z.enum(["recent", "popular"]).default("recent").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) { export async function GET(req: Request) {
@@ -46,7 +50,7 @@ export async function GET(req: Request) {
if (!parsed.success) { if (!parsed.success) {
return NextResponse.json({ error: parsed.error.flatten() }, { status: 400 }); 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 = { const where = {
NOT: { status: "deleted" as const }, NOT: { status: "deleted" as const },
...(boardId ? { boardId } : {}), ...(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; } as const;
const [total, items] = await Promise.all([ const [total, items] = await Promise.all([

View File

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

View File

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

View File

@@ -41,7 +41,7 @@
[게시판/컨텐츠] [게시판/컨텐츠]
7.1 게시글 CRUD API 및 페이지 연동 o 7.1 게시글 CRUD API 및 페이지 연동 o
7.2 목록 페이징/정렬/검색(제목/태그/작성자/기간) 7.2 목록 페이징/정렬/검색(제목/태그/작성자/기간) o
7.3 태그/카테고리 모델 및 UI 7.3 태그/카테고리 모델 및 UI
7.4 첨부 업로드 및 본문 삽입 7.4 첨부 업로드 및 본문 삽입
7.5 추천/신고, 조회수 카운트 7.5 추천/신고, 조회수 카운트