import { HeroBanner } from "@/app/components/HeroBanner"; import PartnerCategorySection from "@/app/components/PartnerCategorySection"; import Link from "next/link"; import HorizontalCardScroller from "@/app/components/HorizontalCardScroller"; import { PostList } from "@/app/components/PostList"; import ProfileLabelIcon from "@/app/svgs/profilelableicon"; import SearchIcon from "@/app/svgs/SearchIcon"; import { RankIcon1st } from "@/app/components/RankIcon1st"; import { RankIcon2nd } from "@/app/components/RankIcon2nd"; import { RankIcon3rd } from "@/app/components/RankIcon3rd"; import { UserAvatar } from "@/app/components/UserAvatar"; import { ImagePlaceholderIcon } from "@/app/components/ImagePlaceholderIcon"; import { BoardPanelClient } from "@/app/components/BoardPanelClient"; import { GradeIcon, getGradeName } from "@/app/components/GradeIcon"; import prisma from "@/lib/prisma"; import { headers } from "next/headers"; export default async function Home({ searchParams }: { searchParams: Promise<{ sort?: "recent" | "popular" } | undefined> }) { const sp = await searchParams; const sort = sp?.sort ?? "recent"; // 로그인된 사용자 정보 가져오기 (기본값: 어드민) let currentUser: { userId: string; nickname: string; profileImage: string | null; points: number; level: number; grade: number; } | null = null; try { const h = await headers(); const cookieHeader = h.get("cookie") || ""; const uid = cookieHeader .split(";") .map((s) => s.trim()) .find((pair) => pair.startsWith("uid=")) ?.split("=")[1]; if (uid) { const user = await prisma.user.findUnique({ where: { userId: decodeURIComponent(uid) }, select: { userId: true, nickname: true, profileImage: true, points: true, level: true, grade: true }, }); if (user) currentUser = user; } } catch (e) { // 에러 무시 } // 로그인되지 않은 경우 어드민 사용자 가져오기 if (!currentUser) { const admin = await prisma.user.findUnique({ where: { nickname: "admin" }, select: { userId: true, nickname: true, profileImage: true, points: true, level: true, grade: true }, }); if (admin) currentUser = admin; } // 내가 쓴 게시글/댓글 수 let myPostsCount = 0; let myCommentsCount = 0; if (currentUser) { myPostsCount = await prisma.post.count({ where: { authorId: currentUser.userId, status: "published" } }); myCommentsCount = await prisma.comment.count({ where: { authorId: currentUser.userId } }); } // 메인페이지 설정 불러오기 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 showPartnerShops: boolean = parsed.showPartnerShops ?? true; const visibleBoardIds: string[] = Array.isArray(parsed.visibleBoardIds) ? parsed.visibleBoardIds : []; // 보드 메타데이터 (메인뷰 타입 포함) const boardsMeta = visibleBoardIds.length ? await prisma.board.findMany({ where: { id: { in: visibleBoardIds } }, select: { id: true, name: true, slug: true, category: { select: { id: true, name: true } }, mainPageViewType: { select: { key: true } }, }, }) : []; const idToMeta = new Map( boardsMeta.map((b) => [ b.id, { id: b.id, name: b.name, slug: b.slug, categoryId: b.category?.id ?? null, categoryName: b.category?.name ?? "", mainTypeKey: b.mainPageViewType?.key, }, ] as const) ); const orderedBoards = visibleBoardIds .map((id) => idToMeta.get(id)) .filter((v): v is any => Boolean(v)); const firstTwo = orderedBoards.slice(0, 2); const restBoards = orderedBoards.slice(2); function formatDateYmd(d: Date) { const yyyy = d.getFullYear(); const mm = String(d.getMonth() + 1).padStart(2, "0"); const dd = String(d.getDate()).padStart(2, "0"); return `${yyyy}.${mm}.${dd}`; } // 게시판 패널 데이터 수집 함수 (모든 sibling boards 포함) const prepareBoardPanelData = async (board: { id: string; name: string; slug: string; categoryId: string | null; categoryName: string; mainTypeKey?: string }) => { // 같은 카테고리의 소분류(게시판) 탭 목록 const siblingBoards = board.categoryId ? await prisma.board.findMany({ where: { categoryId: board.categoryId }, select: { id: true, name: true, slug: true, mainPageViewType: { select: { key: true } } }, orderBy: [{ sortOrder: "asc" }, { name: "asc" }], }) : []; const boardsData = []; for (const sb of siblingBoards) { const isTextMain = sb.mainPageViewType?.key === "main_text"; const isSpecialRank = sb.mainPageViewType?.key === "main_special_rank"; const isPreview = sb.mainPageViewType?.key === "main_preview"; const boardMeta = { id: sb.id, name: sb.name, slug: sb.slug, mainTypeKey: sb.mainPageViewType?.key, }; let specialRankUsers; let previewPosts; let textPosts; if (isSpecialRank) { specialRankUsers = await prisma.user.findMany({ select: { userId: true, nickname: true, points: true, profileImage: true, grade: true }, where: { status: "active" }, orderBy: { points: "desc" }, take: 6, }); } else if (isPreview) { previewPosts = await prisma.post.findMany({ where: { boardId: sb.id, status: "published" }, select: { id: true, title: true, createdAt: true, content: true, attachments: { where: { type: "image" }, orderBy: { sortOrder: "asc" }, take: 1, select: { url: true }, }, stat: { select: { commentsCount: true } }, }, orderBy: { createdAt: "desc" }, take: 6, }); } else if (isTextMain) { textPosts = await prisma.post.findMany({ where: { boardId: sb.id, status: "published" }, select: { id: true, title: true, createdAt: true, stat: { select: { recommendCount: true, commentsCount: true } } }, orderBy: { createdAt: "desc" }, take: 16, }); } // 기본 타입은 PostList가 자체적으로 API를 호출하므로 데이터 미리 가져오지 않음 boardsData.push({ board: boardMeta, categoryName: board.categoryName || board.name, siblingBoards: siblingBoards.map(sb => ({ id: sb.id, name: sb.name, slug: sb.slug, mainTypeKey: sb.mainPageViewType?.key, })), specialRankUsers, previewPosts, textPosts, }); } return { initialBoardId: board.id, boardsData }; }; return (