| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293 |
- 'use client';
- import Link from 'next/link';
- import { Avatar, AvatarImage, AvatarFallback } from '@/components/ui/avatar';
- import { Crown, Medal } from 'lucide-react';
- import type { RankingEntry, RankingType } from '@/types/response/ranking';
- interface Props {
- top3: RankingEntry[];
- type: RankingType;
- }
- function formatAmount(amount: number): string {
- if (amount >= 100000000) {
- return `${(amount / 100000000).toFixed(1)}억`;
- }
- if (amount >= 10000) {
- return `${(amount / 10000).toFixed(1)}만`;
- }
- return amount.toLocaleString('ko-KR');
- }
- function WinnerCard({ entry, rank, type }: { entry: RankingEntry|undefined; rank: 1|2|3; type: RankingType }) {
- const modifier = rank === 1 ? 'first' : rank === 2 ? 'second' : 'third';
- const linkHref = entry && !entry.isAnonymous ? `/channel/${entry.memberID}` : '#';
- if (!entry) {
- return (
- <div className={`ranking-podium__winner ranking-podium__winner--${modifier} ranking-podium__winner--empty`}>
- <div className="ranking-podium__rank-number">{rank}</div>
- <Avatar className="ranking-podium__avatar">
- <AvatarFallback>-</AvatarFallback>
- </Avatar>
- <div className="ranking-podium__name">대기 중</div>
- <div className="ranking-podium__amount">-</div>
- </div>
- );
- }
- return (
- <div className={`ranking-podium__winner ranking-podium__winner--${modifier}`}>
- {rank === 1 && (
- <>
- <div className="ranking-podium__shimmer" aria-hidden="true" />
- <Crown className="ranking-podium__crown" size={44} aria-hidden="true" />
- </>
- )}
- {rank !== 1 && (
- <Medal className="ranking-podium__medal" size={32} aria-hidden="true" />
- )}
- <div className="ranking-podium__rank-number">{rank}</div>
- <Link href={linkHref} className="ranking-podium__link">
- <Avatar className="ranking-podium__avatar">
- {(entry.channelThumb ?? entry.memberThumb) ? <AvatarImage src={(entry.channelThumb ?? entry.memberThumb)!} alt={entry.memberName} /> : null}
- <AvatarFallback>{entry.memberName?.[0] ?? '?'}</AvatarFallback>
- </Avatar>
- <div className="ranking-podium__name">{entry.memberName}</div>
- {entry.channelName && entry.channelName !== entry.memberName ? (
- <div className="ranking-podium__channel">{entry.channelName}</div>
- ) : null}
- </Link>
- <div className="ranking-podium__amount">
- {formatAmount(entry.moneyAmount)}
- {type === 'donor' ? 'P' : '원'}
- </div>
- {type !== 'donor' && entry.donorCount > 0 ? (
- <div className="ranking-podium__meta">후원자 {entry.donorCount.toLocaleString('ko-KR')}명</div>
- ) : null}
- </div>
- );
- }
- export default function Podium({ top3, type }: Props) {
- if (top3.length === 0) {
- return null;
- }
- const first = top3.find((e) => e.rank === 1);
- const second = top3.find((e) => e.rank === 2);
- const third = top3.find((e) => e.rank === 3);
- return (
- <div className="ranking-podium" role="region" aria-label="상위 3위 시상대">
- <div className="ranking-podium__stage">
- <WinnerCard entry={second} rank={2} type={type} />
- <WinnerCard entry={first} rank={1} type={type} />
- <WinnerCard entry={third} rank={3} type={type} />
- </div>
- </div>
- );
- }
|