page.tsx 3.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125
  1. 'use client';
  2. import './style.scss';
  3. import { useState, useEffect } from 'react';
  4. import { LoginLogType } from '@/constants/common';
  5. import { fetchApi, throwError, formatDate } from '@/lib/utils/client';
  6. import type { ExpLogsResponse } from '@/types/response/account/expLogs';
  7. import Loading from '@/app/component/Loading';
  8. import Pagination from '@/app/component/Pagination';
  9. import NavTabs from '../navTabs';
  10. export default function ExpLogs()
  11. {
  12. const [error, setError] = useState<string>('');
  13. const [loading, setLoading] = useState<boolean>(true);
  14. const [page, setPage] = useState<number>(1);
  15. const [type, setType] = useState<LoginLogType>(LoginLogType.Today);
  16. const [data, setData] = useState<ExpLogsResponse>({
  17. total: 0,
  18. list: []
  19. });
  20. useEffect(() => {
  21. if (error) {
  22. alert(error);
  23. setError('');
  24. }
  25. }, [error]);
  26. useEffect(() => {
  27. setLoading(true);
  28. fetchApi<ExpLogsResponse>(`/api/mypage/exp-logs?type=${type}&page=${page}&perPage=20`).then((res) => {
  29. throwError(res);
  30. setData(res.data!);
  31. }).catch(err => {
  32. setError(err.message);
  33. }).finally(() => {
  34. setLoading(false);
  35. });
  36. }, [type, page]);
  37. useEffect(() => {
  38. setPage(1);
  39. }, [type]);
  40. const tabItems = [
  41. { label: "오늘", value: LoginLogType.Today },
  42. { label: "1주일", value: LoginLogType.Week },
  43. { label: "1개월", value: LoginLogType.Month },
  44. { label: "3개월", value: LoginLogType.QuarterYear },
  45. { label: "6개월", value: LoginLogType.HalfYear }
  46. ];
  47. return (
  48. <>
  49. <NavTabs />
  50. <div id="expLogs">
  51. { loading && <Loading /> }
  52. <h1>경험치 내역</h1>
  53. <table className="table-auto max-2xl:w-full 2xl:w-[1000px]">
  54. <caption>
  55. <div className="grid grid-cols-[auto,1fr] gap-4 items-center">
  56. <div>
  57. 합계: {data.total}
  58. </div>
  59. <div id="expTypeTab" className="justify-self-end">
  60. {tabItems.map((item, i) => (
  61. <button type="button" key={i} className={`flex-1 py-2 px-4 text-center text-sm font-medium
  62. ${type === item.value ? "border-b-2 border-blue-500 text-blue-500" : "text-gray-500"}
  63. `} onClick={() => setType(item.value)}>{item.label}
  64. </button>
  65. ))}
  66. </div>
  67. </div>
  68. </caption>
  69. <colgroup>
  70. <col width="20%"/>
  71. <col />
  72. <col width="15%"/>
  73. <col width="15%"/>
  74. </colgroup>
  75. <thead>
  76. <tr>
  77. <th>일시</th>
  78. <th>사유</th>
  79. <th>변동</th>
  80. <th>잔액</th>
  81. </tr>
  82. </thead>
  83. <tbody>
  84. {data.list.length > 0 ? (
  85. data.list.map((row) => (
  86. <tr key={row.id} className="hover:bg-gray-100">
  87. <td>{formatDate(row.createdAt)}</td>
  88. <td>{row.reason}</td>
  89. <td className={`font-semibold ${row.amount > 0 ? "text-green-500" : "text-red-500"}`}>
  90. {row.amount > 0 ? `+${row.amount}` : row.amount}
  91. </td>
  92. <td>{row.balance.toLocaleString()}</td>
  93. </tr>
  94. ))
  95. ) : (
  96. <tr>
  97. <td colSpan={4} className="border p-2 text-center text-gray-500">
  98. 기록이 없습니다.
  99. </td>
  100. </tr>
  101. )}
  102. </tbody>
  103. {data.list.length > 0 && (
  104. <tfoot>
  105. <tr>
  106. <td colSpan={4}>
  107. <Pagination total={data.total} page={page} perPage={20} onChange={setPage} />
  108. </td>
  109. </tr>
  110. </tfoot>
  111. )}
  112. </table>
  113. </div>
  114. </>
  115. );
  116. }