page.tsx 4.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156
  1. 'use client';
  2. import './style.scss';
  3. import { useState, useEffect } from 'react';
  4. import { LoginLogType } from '@/constants/common';
  5. import { fetchApi, getDateTime } from '@/lib/utils/client';
  6. import type { ChargeLogsResponse } from '@/types/response/account/chargeLogs';
  7. import Loading from '@/app/component/Loading';
  8. import Pagination from '@/app/component/Pagination';
  9. import NavTabs from '../navTabs';
  10. const STATUS_MAP: Record<string, { label: string; cls: string }> = {
  11. Paid: { label: '완료', cls: 'status--paid' },
  12. Pending: { label: '대기', cls: 'status--pending' },
  13. WaitingDeposit: { label: '입금대기', cls: 'status--pending' },
  14. Failed: { label: '실패', cls: 'status--failed' },
  15. Cancelled: { label: '취소', cls: 'status--cancelled' }
  16. };
  17. const METHOD_MAP: Record<string, string> = {
  18. Card: '신용카드',
  19. VirtualAccount: '가상계좌',
  20. Mobile: '휴대폰',
  21. Transfer: '계좌이체',
  22. NaverPay: '네이버페이',
  23. KakaoPay: '카카오페이',
  24. Payco: '페이코',
  25. Integrated: '통합결제'
  26. };
  27. export default function ChargeLogs()
  28. {
  29. const [error, setError] = useState<string>('');
  30. const [loading, setLoading] = useState<boolean>(true);
  31. const [page, setPage] = useState<number>(1);
  32. const [type, setType] = useState<LoginLogType>(LoginLogType.Today);
  33. const [data, setData] = useState<ChargeLogsResponse>({
  34. total: 0,
  35. list: []
  36. });
  37. useEffect(() => {
  38. if (error) {
  39. alert(error);
  40. setError('');
  41. }
  42. }, [error]);
  43. useEffect(() => {
  44. setLoading(true);
  45. fetchApi<ChargeLogsResponse>(`/api/mypage/charge-logs?type=${type}&page=${page}&perPage=20`).then((res) => {
  46. setData(res.data!);
  47. }).catch(err => {
  48. setError(err.message);
  49. }).finally(() => {
  50. setLoading(false);
  51. });
  52. }, [type, page]);
  53. useEffect(() => {
  54. setPage(1);
  55. }, [type]);
  56. const tabItems = [
  57. { label: "오늘", value: LoginLogType.Today },
  58. { label: "1주일", value: LoginLogType.Week },
  59. { label: "1개월", value: LoginLogType.Month },
  60. { label: "3개월", value: LoginLogType.QuarterYear },
  61. { label: "6개월", value: LoginLogType.HalfYear }
  62. ];
  63. const getStatus = (status: string) => STATUS_MAP[status] ?? { label: status, cls: '' };
  64. const getMethod = (method: string) => METHOD_MAP[method] ?? method;
  65. return (
  66. <>
  67. <NavTabs />
  68. <div id="chargeLogs">
  69. {loading && <Loading />}
  70. <h1>(P) 충전 내역</h1>
  71. <div className="charge-logs__header">
  72. <div className="charge-logs__summary">합계: {data.total}</div>
  73. <div className="charge-logs__tabs">
  74. {tabItems.map((item, i) => (
  75. <button type="button" key={i} className={type === item.value ? 'active' : ''}
  76. onClick={() => setType(item.value)}>{item.label}
  77. </button>
  78. ))}
  79. </div>
  80. </div>
  81. <section className="charge-logs__list">
  82. <article>
  83. <ul>
  84. <li>일시</li>
  85. <li>주문번호</li>
  86. <li>결제 수단</li>
  87. <li>결제 금액</li>
  88. <li>포인트</li>
  89. <li>상태</li>
  90. </ul>
  91. </article>
  92. <article>
  93. {data.list.length > 0 ? (
  94. data.list.map((row) => {
  95. const st = getStatus(row.status);
  96. return (
  97. <section key={row.id}>
  98. {/* PC */}
  99. <ol>
  100. <li>{getDateTime(row.paidAt ?? row.createdAt)}</li>
  101. <li className="charge-logs__order-id">{row.orderID}</li>
  102. <li>{getMethod(row.paymentMethod)}</li>
  103. <li>{row.amount.toLocaleString()}원</li>
  104. <li className="amount-plus">+{row.pointAmount.toLocaleString()}P</li>
  105. <li><span className={st.cls}>{st.label}</span></li>
  106. </ol>
  107. {/* Mobile */}
  108. <dl hidden>
  109. <dt>
  110. <div className='flex justify-between'>
  111. <div>{row.amount.toLocaleString()}원 충전</div>
  112. <div>
  113. <small className="charge-logs__order-id">{row.orderID}</small>
  114. </div>
  115. </div>
  116. </dt>
  117. <dd>
  118. <ul>
  119. <li className="amount-plus">+{row.pointAmount.toLocaleString()}P</li>
  120. <li><span className={st.cls}>{st.label}</span></li>
  121. <li>{getDateTime(row.paidAt ?? row.createdAt)}</li>
  122. </ul>
  123. </dd>
  124. </dl>
  125. </section>
  126. );
  127. })
  128. ) : (
  129. <p className="empty">충전 기록이 없습니다.</p>
  130. )}
  131. </article>
  132. </section>
  133. {data.list.length > 0 && (
  134. <Pagination total={data.total} page={page} perPage={20} onChange={setPage} />
  135. )}
  136. </div>
  137. </>
  138. );
  139. }