| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788899091 |
- import '@/app/styles/community.scss';
- import '@/app/styles/data-table.scss';
- import { Metadata } from 'next';
- import Link from 'next/link';
- import { fetchTrackRecordLeaderboard } from '@/lib/api/community';
- import TierBadge from '@/components/community/TierBadge';
- export const metadata: Metadata = {
- title: '예측 적중률 리더보드 — 개미투자',
- description: '종목 예측글 채점 기반 적중률 순위 (표본 10건 이상 · 전체 기간)'
- };
- const PAGE_SIZE = 50;
- type Props = {
- searchParams: Promise<{
- page?: string;
- }>;
- };
- export default async function TrackRecordLeaderboardPage({ searchParams }: Props)
- {
- const query = await searchParams;
- const page = Math.max(Number(query.page) || 1, 1);
- const res = await fetchTrackRecordLeaderboard({ page });
- const data = res.success ? res.data : null;
- const rows = data?.list ?? [];
- const totalPages = data ? Math.max(Math.ceil(data.total / PAGE_SIZE), 1) : 1;
- return (
- <div className='track-leaderboard'>
- <div className='track-leaderboard__head'>
- <h1 className='track-leaderboard__title'>예측 적중률 리더보드</h1>
- <span className='track-leaderboard__subtitle'>
- 종목 예측글이 채점된 회원 순위입니다 (표본 10건 이상 · 전체 기간). 순위는 명예·프로필 배지만 부여됩니다.
- </span>
- </div>
- {!res.success ? (
- <div className='track-leaderboard__error' role='alert'>리더보드를 불러오지 못했습니다. 잠시 후 다시 시도해 주세요.</div>
- ) : rows.length === 0 ? (
- <div className='track-leaderboard__empty'>아직 채점된 예측이 있는 회원이 없습니다.</div>
- ) : (
- <div className='track-leaderboard__table-wrap'>
- <table className='data-table'>
- <caption className='data-table__caption data-table__caption--sr'>
- 예측 적중률 리더보드 — 순위·닉네임·적중률·최고 스트릭·표본수·티어
- </caption>
- <thead>
- <tr>
- <th scope='col' data-align='center' data-priority='high'>순위</th>
- <th scope='col' data-align='left' data-priority='high'>닉네임</th>
- <th scope='col' data-align='right' data-priority='high'>적중률</th>
- <th scope='col' data-align='right' data-priority='medium'>최고 스트릭</th>
- <th scope='col' data-align='right' data-priority='medium'>표본수</th>
- <th scope='col' data-align='center' data-priority='low'>티어</th>
- </tr>
- </thead>
- <tbody>
- {rows.map(row => (
- <tr key={row.sid}>
- <td data-align='center'><span className='track-leaderboard__rank'>{row.rank}</span></td>
- <td data-align='left'>
- <Link href={`/user/${row.sid}`} className='track-leaderboard__name'>{row.name}</Link>
- </td>
- <td data-align='right'><span className='track-leaderboard__hitrate'>{row.hitRate.toFixed(1)}%</span></td>
- <td data-align='right'>{row.bestStreak.toLocaleString()}</td>
- <td data-align='right'>{row.predictions.toLocaleString()}</td>
- <td data-align='center'><TierBadge tierCode={row.tierCode} /></td>
- </tr>
- ))}
- </tbody>
- </table>
- </div>
- )}
- {res.success && rows.length > 0 && data && data.total > PAGE_SIZE && (
- <nav className='track-leaderboard__actions' aria-label='페이지'>
- {page > 1 && (
- <Link href={`/ranking/track-record?page=${page - 1}`} className='track-leaderboard__btn'>이전</Link>
- )}
- <span className='track-leaderboard__rank'>{page} / {totalPages}</span>
- {page < totalPages && (
- <Link href={`/ranking/track-record?page=${page + 1}`} className='track-leaderboard__btn'>다음</Link>
- )}
- </nav>
- )}
- </div>
- );
- }
|