'use client'; import { useState, useEffect, useMemo } from 'react'; import Link from 'next/link'; import { fetchApi, getDateTime } from '@/lib/utils/client'; import type { WalletWithdrawResponse } from '@/types/response/wallet/withdraw'; import { LoginLogType } from '@/constants/common'; import { PERIOD_TABS, WITHDRAW_STATUS_MAP, WITHHOLDING_TAX_RATE, MIN_WITHDRAW_AMOUNT } from '../constants'; import Loading from '@/app/component/Loading'; import Pagination from '@/app/component/Pagination'; export default function WalletWithdrawPage() { const [loading, setLoading] = useState(true); const [submitting, setSubmitting] = useState(false); const [page, setPage] = useState(1); const [period, setPeriod] = useState(LoginLogType.Month); const [data, setData] = useState({ total: 0, withdrawableBalance: 0, accounts: [], list: [], }); const [amount, setAmount] = useState(''); const [selectedAccountID, setSelectedAccountID] = useState(0); const numericAmount = useMemo(() => { const n = parseInt(amount, 10); return isNaN(n) ? 0 : n; }, [amount]); const withholdingTax = useMemo(() => Math.floor(numericAmount * WITHHOLDING_TAX_RATE), [numericAmount]); const netAmount = useMemo(() => numericAmount - withholdingTax, [numericAmount, withholdingTax]); const canSubmit = useMemo(() => { return ( selectedAccountID > 0 && numericAmount >= MIN_WITHDRAW_AMOUNT && numericAmount <= data.withdrawableBalance && !submitting ); }, [selectedAccountID, numericAmount, data.withdrawableBalance, submitting]); useEffect(() => { setLoading(true); fetchApi(`/api/studio/wallet/withdraw?period=${period}&page=${page}&perPage=20`) .then(res => { if (res.data) { setData(res.data); // 계좌가 1개면 자동 선택 if (res.data.accounts.length === 1 && selectedAccountID === 0) { setSelectedAccountID(res.data.accounts[0].id); } } }) .catch(() => {}) .finally(() => setLoading(false)); }, [period, page]); useEffect(() => { setPage(1); }, [period]); const handleSubmit = async () => { if (!canSubmit) { return; } const selectedAccount = data.accounts.find(a => a.id === selectedAccountID); const confirmed = confirm( `출금 신청하시겠습니까?\n\n` + `입금 계좌: ${selectedAccount?.bankName} ${selectedAccount?.accountNumber}\n` + `신청 금액: ${numericAmount.toLocaleString()}원\n` + `원천징수(3.3%): -${withholdingTax.toLocaleString()}원\n` + `실수령액: ${netAmount.toLocaleString()}원` ); if (!confirmed) { return; } setSubmitting(true); try { await fetchApi('/api/studio/wallet/withdraw', { method: 'POST', body: { accountID: selectedAccountID, amount: numericAmount }, }); alert('출금 신청이 완료되었습니다.'); setAmount(''); // 목록 새로고침 const res = await fetchApi(`/api/studio/wallet/withdraw?period=${period}&page=1&perPage=20`); if (res.data) { setData(res.data); } setPage(1); } catch (err: unknown) { alert(err instanceof Error ? err.message : '출금 신청에 실패했습니다.'); } finally { setSubmitting(false); } }; const getStatus = (status: string) => WITHDRAW_STATUS_MAP[status] ?? { label: status, cls: '' }; return (

출금

{loading && } {/* Withdraw Form */}
{data.withdrawableBalance.toLocaleString()}원 (M) 출금 가능
{/* 계좌 미등록 경고 */} {data.accounts.length === 0 && (
계좌가 등록되지 않았습니다. 계좌 등록하기
)} {/* 계좌 선택 */} {data.accounts.length > 0 && (
계좌 관리
)} {/* 금액 입력 */}
setAmount(e.target.value.replace(/\D/g, ''))} disabled={data.accounts.length === 0} />
{/* 차감 프리뷰 */} {numericAmount > 0 && (
신청 금액 {numericAmount.toLocaleString()}원
원천징수 (3.3%) -{withholdingTax.toLocaleString()}원
실수령액 {netAmount.toLocaleString()}원
)} {/* 안내사항 */}
  • 최소 출금 금액: {MIN_WITHDRAW_AMOUNT.toLocaleString()}원
  • 원천징수 3.3% (소득세 3% + 지방소득세 0.3%)
  • 매월 10일까지 신청 시 당월 말 입금
{/* 제출 */}
{/* Withdraw History */}

출금 내역

합계: {data.total}건
{PERIOD_TABS.map((tab) => ( ))}
{data.list.length > 0 ? ( data.list.map((row) => { const st = getStatus(row.status); return ( ); }) ) : ( )}
신청일 신청 금액 원천징수 실수령액 계좌 상태
{getDateTime(row.requestedAt)} {row.requestedAmount.toLocaleString()}원 -{row.withholdingTax.toLocaleString()}원 {row.netAmount.toLocaleString()}원 {row.bankName} {row.accountNumber} {st.label}
출금 내역이 없습니다.
{data.total > 0 && ( )}
); }