'use client'; import { useCallback, useEffect, useState } from 'react'; import { fetchApi, cn } from '@/lib/utils/client'; import { formatBpPercent, bpDirection, formatTokenNumber } from '@/lib/utils/paper'; import type { PaperAccountResponse, PaperMyRankResponse } from '@/types/paper'; import Loading from '@/app/component/Loading'; import PaperDepositWithdrawModal from './PaperDepositWithdrawModal'; // 내 계좌 카드 — 잔액/예약/평가자산/좌수/누적수익률/순위 + 입금·출금 모달. // 계좌 미개설(hasAccount=false) 시 첫 입금 안내. export default function PaperAccountCard() { const [account, setAccount] = useState(null); const [rank, setRank] = useState(null); const [loading, setLoading] = useState(true); const [modal, setModal] = useState<'deposit'|'withdraw'|null>(null); const load = useCallback(async () => { setLoading(true); const [accRes, rankRes] = await Promise.all([ fetchApi('/api/paper/account', { silent: true }), fetchApi('/api/paper/leaderboard/me?sort=return&period=all', { silent: true }) ]); setAccount(accRes.success ? (accRes.data ?? null) : null); setRank(rankRes.success ? (rankRes.data ?? null) : null); setLoading(false); }, []); useEffect(() => { load(); }, [load]); const handleDone = useCallback(() => { setModal(null); load(); }, [load]); if (loading) { return (
); } if (!account || !account.hasAccount) { return ( <>
아직 모의투자 계좌가 없어요

지갑 토큰을 입금하면 계좌가 자동으로 개설됩니다.
입금한 토큰으로 실제 종목을 매매하고, 언제든 다시 지갑으로 출금할 수 있어요.

{modal === 'deposit' && ( setModal(null)} onDone={handleDone} /> )} ); } const returnDir = bpDirection(account.cumReturnBp); return ( <>
가용 토큰 {formatTokenNumber(account.token)}
매수 예약 {formatTokenNumber(account.reservedToken)}
평가자산 {formatTokenNumber(account.equity)}
보유 좌수 {account.units.toLocaleString('ko-KR', { maximumFractionDigits: 4 })}
누적 수익률 {formatBpPercent(account.cumReturnBp)}
순위 (수익률·전체) {rank && rank.hasRank ? `${rank.rank.toLocaleString()}위 / ${rank.total.toLocaleString()}` : '미등재'}
{modal && ( setModal(null)} onDone={handleDone} /> )} ); }