123
This commit is contained in:
@@ -3,6 +3,11 @@ import { HeroBanner } from "@/app/components/HeroBanner";
|
||||
import { BoardToolbar } from "@/app/components/BoardToolbar";
|
||||
import { headers } from "next/headers";
|
||||
import prisma from "@/lib/prisma";
|
||||
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";
|
||||
|
||||
// Next 15: params/searchParams가 Promise가 될 수 있어 안전 언랩 처리합니다.
|
||||
export default async function BoardDetail({ params, searchParams }: { params: any; searchParams: any }) {
|
||||
@@ -29,15 +34,15 @@ export default async function BoardDetail({ params, searchParams }: { params: an
|
||||
});
|
||||
const isSpecialRanking = boardView?.listViewType?.key === "list_special_rank";
|
||||
|
||||
let rankingItems: { userId: string; nickname: string; points: number }[] = [];
|
||||
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 },
|
||||
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 }));
|
||||
rankingItems = topUsers.map((u) => ({ userId: u.userId, nickname: u.nickname, points: u.points, profileImage: u.profileImage, grade: u.grade }));
|
||||
}
|
||||
return (
|
||||
<div className="space-y-6">
|
||||
@@ -54,24 +59,46 @@ export default async function BoardDetail({ params, searchParams }: { params: an
|
||||
{!isSpecialRanking && <BoardToolbar boardId={board?.slug} />}
|
||||
<div className="p-0">
|
||||
{isSpecialRanking ? (
|
||||
<div className="rounded-xl border border-neutral-200 overflow-hidden">
|
||||
<div className="px-4 py-3 border-b border-neutral-200 flex items-center justify-between bg-[#f6f4f4]">
|
||||
<h2 className="text-sm text-neutral-700">포인트 랭킹</h2>
|
||||
</div>
|
||||
<ol className="divide-y divide-neutral-200">
|
||||
{rankingItems.map((i, idx) => (
|
||||
<li key={i.userId} className="px-4 py-3 flex items-center justify-between">
|
||||
<div className="flex items-center gap-3 min-w-0">
|
||||
<span className="inline-flex items-center justify-center w-6 h-6 rounded-full bg-neutral-900 text-white text-xs">{idx + 1}</span>
|
||||
<span className="truncate text-neutral-900 font-medium">{i.nickname || "회원"}</span>
|
||||
<div className="w-full">
|
||||
<div className="grid grid-cols-1 md:grid-cols-2 lg:grid-cols-3 gap-[32px]">
|
||||
{rankingItems.map((i, idx) => {
|
||||
const rank = idx + 1;
|
||||
return (
|
||||
<div key={i.userId} className="border-t border-[#d5d5d5]">
|
||||
<div className="flex gap-[16px] items-center p-[16px]">
|
||||
<div className="flex items-center gap-[8px] shrink-0">
|
||||
{(rank === 1 || rank === 2 || rank === 3) && (
|
||||
<div className="relative w-[20px] h-[20px] shrink-0">
|
||||
{rank === 1 && <RankIcon1st />}
|
||||
{rank === 2 && <RankIcon2nd />}
|
||||
{rank === 3 && <RankIcon3rd />}
|
||||
</div>
|
||||
)}
|
||||
<div className="bg-white border border-[#d5d5d5] px-[16px] py-[5px] rounded-[12px] text-[14px] text-[#5c5c5c] shrink-0">
|
||||
{rank}위
|
||||
</div>
|
||||
<div className="flex items-center gap-[10px] shrink-0 pl-0 pr-[15px] py-0">
|
||||
<UserAvatar src={i.profileImage} alt={i.nickname || "프로필"} width={36} height={36} className="rounded-full" />
|
||||
<span className="text-[16px] text-[#5c5c5c] leading-[16px] tracking-[-0.28px] whitespace-nowrap">
|
||||
{i.nickname || "회원"}
|
||||
</span>
|
||||
<GradeIcon grade={i.grade} width={20} height={20} />
|
||||
</div>
|
||||
</div>
|
||||
<div className="flex items-center gap-[13px] shrink-0 ml-auto">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="16" height="16" viewBox="0 0 16 16" fill="none" className="shrink-0">
|
||||
<path d="M8.17377 0.0481988C8.1834 0.0326271 8.19596 0.0201252 8.21037 0.0117499C8.22478 0.00337451 8.24062 -0.000628204 8.25656 7.99922e-05C8.2725 0.000788189 8.28806 0.0061865 8.30194 0.0158187C8.31582 0.0254509 8.3276 0.0390338 8.33629 0.0554196L11.3323 5.55973C11.3575 5.60512 11.4038 5.62472 11.4468 5.60718L15.8683 3.80198C15.9441 3.77104 16.0174 3.85666 15.9963 3.95053L14.2584 16H1.74226L0.00344328 3.95156C-0.00125237 3.93019 -0.0011435 3.90765 0.00375838 3.88635C0.00866025 3.86505 0.0181727 3.84576 0.0312889 3.83054C0.0444051 3.81532 0.0606369 3.80472 0.0782661 3.79988C0.0958953 3.79503 0.114266 3.79612 0.131434 3.80302L4.55889 5.61131C4.59846 5.62678 4.64309 5.61131 4.66835 5.57005L8.17461 0.0481988H8.17377Z" fill="#FFB625"/>
|
||||
</svg>
|
||||
<span className="text-[16px] font-semibold text-[#5c5c5c] leading-[22px]">{i.points.toLocaleString()}</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div className="shrink-0 text-sm text-neutral-700">{i.points}점</div>
|
||||
</li>
|
||||
))}
|
||||
{rankingItems.length === 0 && (
|
||||
<li className="px-4 py-10 text-center text-neutral-500">랭킹 데이터가 없습니다.</li>
|
||||
)}
|
||||
</ol>
|
||||
);
|
||||
})}
|
||||
</div>
|
||||
{rankingItems.length === 0 && (
|
||||
<div className="px-4 py-10 text-center text-neutral-500">랭킹 데이터가 없습니다.</div>
|
||||
)}
|
||||
</div>
|
||||
) : (
|
||||
<PostList
|
||||
|
||||
Reference in New Issue
Block a user