page.tsx 3.4 KB

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