import { PostList } from "@/app/components/PostList"; import { HeroBanner } from "@/app/components/HeroBanner"; import Link from "next/link"; import { BoardToolbar } from "@/app/components/BoardToolbar"; import { headers } from "next/headers"; import prisma from "@/lib/prisma"; import { notFound } from "next/navigation"; import { UserAvatar } from "@/app/components/UserAvatar"; import { RankIcon1st } from "@/app/components/RankIcon1st"; import { RankIcon2nd } from "@/app/components/RankIcon2nd"; import { RankIcon3rd } from "@/app/components/RankIcon3rd"; import { GradeIcon } from "@/app/components/GradeIcon"; import AttendanceCalendar from "@/app/components/AttendanceCalendar"; // Next 15: params/searchParams가 Promise가 될 수 있어 안전 언랩 처리합니다. export default async function BoardDetail({ params, searchParams }: { params: any; searchParams: any }) { const p = params?.then ? await params : params; const sp = searchParams?.then ? await searchParams : searchParams; const idOrSlug = p.id as string; const sort = (sp?.sort as "recent" | "popular" | "views" | "likes" | "comments" | undefined) ?? "recent"; // 보드 slug 조회 (새 글 페이지 프리셋 전달) const h = await headers(); const host = h.get("host") ?? "localhost:3000"; const proto = h.get("x-forwarded-proto") ?? "http"; const base = process.env.NEXT_PUBLIC_BASE_URL || `${proto}://${host}`; // 로그인 여부 파악 const cookieHeader = h.get("cookie") || ""; const uid = cookieHeader .split(";") .map((s) => s.trim()) .find((pair) => pair.startsWith("uid=")) ?.split("=")[1]; const isLoggedIn = !!uid; const res = await fetch(new URL("/api/boards", base).toString(), { cache: "no-store" }); const { boards } = await res.json(); const board = (boards || []).find((b: any) => b.slug === idOrSlug || b.id === idOrSlug); if (!board) { return notFound(); } const id = board.id as string; const siblingBoards = (boards || []).filter((b: any) => b.category?.id && b.category.id === board?.category?.id); const categoryName = board?.category?.name ?? ""; // 메인배너 표시 설정 const SETTINGS_KEY = "mainpage_settings" as const; const settingRow = await prisma.setting.findUnique({ where: { key: SETTINGS_KEY } }); const parsed = settingRow ? JSON.parse(settingRow.value as string) : {}; const showBanner: boolean = parsed.showBanner ?? true; // 리스트 뷰 타입 확인 (특수랭킹/출석부 등) const boardView = await prisma.board.findUnique({ where: { id }, select: { listViewType: { select: { key: true } } }, }); const isSpecialRanking = boardView?.listViewType?.key === "list_special_rank"; const isAttendance = boardView?.listViewType?.key === "list_special_attendance"; let rankingItems: { userId: string; nickname: string; points: number; profileImage: string | null; grade: number }[] = []; if (isSpecialRanking) { const topUsers = await prisma.user.findMany({ select: { userId: true, nickname: true, points: true, profileImage: true, grade: true }, where: { status: "active" }, orderBy: { points: "desc" }, take: 100, }); rankingItems = topUsers.map((u) => ({ userId: u.userId, nickname: u.nickname, points: u.points, profileImage: u.profileImage, grade: u.grade })); } return (
{/* 상단 배너 (서브카테고리 표시) */} {showBanner ? (
({ id: b.id, name: b.name, href: `/boards/${b.slug}` }))} activeSubId={id} />
) : (
{siblingBoards.map((b: any) => ( {b.name} ))}
)} {/* 검색/필터 툴바 + 리스트 */}
{!isSpecialRanking && !isAttendance && }
{isSpecialRanking ? (
{rankingItems.map((i, idx) => { const rank = idx + 1; return (
{(rank === 1 || rank === 2 || rank === 3) && (
{rank === 1 && } {rank === 2 && } {rank === 3 && }
)}
{rank}위
{i.nickname || "회원"}
{i.points.toLocaleString()}
); })}
{rankingItems.length === 0 && (
랭킹 데이터가 없습니다.
)}
) : isAttendance ? (
) : ( )}
); }