page.tsx 3.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105
  1. 'use client';
  2. import { useState, useEffect } from 'react';
  3. import Link from 'next/link';
  4. import { LogOut } from 'lucide-react';
  5. import { fetchApi, getDateTime } from '@/lib/utils/client';
  6. import type { WalletBalanceResponse } from '@/types/response/wallet/balance';
  7. import { TRANSACTION_TYPE_MAP } from '../constants';
  8. import Loading from '@/app/component/Loading';
  9. export default function WalletBalancePage() {
  10. const [loading, setLoading] = useState(true);
  11. const [data, setData] = useState<WalletBalanceResponse|null>(null);
  12. useEffect(() => {
  13. fetchApi<WalletBalanceResponse>('/api/studio/wallet/balance')
  14. .then(res => {
  15. if (res.data) {
  16. setData(res.data);
  17. }
  18. })
  19. .catch(() => {})
  20. .finally(() => setLoading(false));
  21. }, []);
  22. if (loading || !data) {
  23. return <Loading />;
  24. }
  25. return (
  26. <div className="studio-page wallet">
  27. <div className="studio-page__header">
  28. <h1 className="studio-page__title">잔액 현황</h1>
  29. </div>
  30. {/* Summary Cards */}
  31. <div className="wallet__cards">
  32. <div className="wallet__card">
  33. <span className="wallet__card-label">출금 가능 잔액 (M)</span>
  34. <div className="wallet__card-value wallet__card-value--money">
  35. {data.withdrawableBalance.toLocaleString()}원
  36. </div>
  37. </div>
  38. <div className="wallet__card">
  39. <span className="wallet__card-label">누적 수익</span>
  40. <div className="wallet__card-value">
  41. {data.totalEarned.toLocaleString()}원
  42. </div>
  43. </div>
  44. <div className="wallet__card">
  45. <span className="wallet__card-label">누적 출금</span>
  46. <div className="wallet__card-value">
  47. {data.totalWithdrawn.toLocaleString()}원
  48. </div>
  49. </div>
  50. </div>
  51. {/* Actions */}
  52. <div className="wallet__actions">
  53. <Link href="/studio/wallet/withdraw" className="wallet__action-btn wallet__action-btn--primary">
  54. <LogOut className="size-4" />
  55. 출금하기
  56. </Link>
  57. </div>
  58. {/* Recent Transactions */}
  59. <h2 className="wallet__section-title">최근 거래 내역</h2>
  60. <div className="wallet__table-wrap">
  61. <table className="wallet__table">
  62. <thead>
  63. <tr>
  64. <th>일시</th>
  65. <th>유형</th>
  66. <th>내용</th>
  67. <th style={{ textAlign: 'right' }}>금액</th>
  68. <th style={{ textAlign: 'right' }}>잔액</th>
  69. </tr>
  70. </thead>
  71. <tbody>
  72. {data.recentTransactions.length > 0 ? (
  73. data.recentTransactions.map((tx) => (
  74. <tr key={tx.id}>
  75. <td>{getDateTime(tx.createdAt)}</td>
  76. <td>{TRANSACTION_TYPE_MAP[tx.type] ?? tx.type}</td>
  77. <td>{tx.description}</td>
  78. <td style={{ textAlign: 'right' }}>
  79. <span className={tx.amount >= 0 ? 'wallet__amount--plus' : 'wallet__amount--minus'}>
  80. {tx.amount >= 0 ? '+' : ''}{tx.amount.toLocaleString()}원
  81. </span>
  82. </td>
  83. <td style={{ textAlign: 'right' }}>{tx.balance.toLocaleString()}원</td>
  84. </tr>
  85. ))
  86. ) : (
  87. <tr>
  88. <td colSpan={5} className="wallet__empty">거래 내역이 없습니다.</td>
  89. </tr>
  90. )}
  91. </tbody>
  92. </table>
  93. </div>
  94. </div>
  95. );
  96. }