1+ import { useEffect , useState } from "react" ;
2+ import PaginationNavigator from "../../layout/PaginationNavigator" ;
3+ import { X } from "lucide-react"
4+ import styles from "../rank/rank.module.scss" ;
5+ import FlexibleTable from "../../shared/table/FlexibleTable" ;
6+ import TableBackGroundCard from "../../shared/TableBackGroundCard" ;
7+ import { useApiQuery } from "../../hooks/useApiQuery" ;
8+ import { useQueryParam } from "../../hooks/QueryParam" ;
9+ import axios from "axios" ;
10+
11+ const initColumns = [
12+ { accessorKey : "id" , header : "순번" } ,
13+ { accessorKey : "nickname" , header : "닉네임" } ,
14+ { accessorKey : "lastLogin" , header : "최근 로그인" } ,
15+ { accessorKey : "createdAt" , header : "가입 날짜" } ,
16+ ] ;
17+
18+ const usersRequest = async ( params ) => {
19+ const response = await axios . get ( `/admin/users` , { params} ) ;
20+ return response . data ;
21+ } ;
22+
23+ const UserList = ( ) => {
24+ const [ searchTerm , setSearchTerm ] = useState ( "" ) ;
25+ const [ params , setParams ] = useQueryParam ( ) ;
26+ const [ tableRows , setTableRows ] = useState ( [ ] ) ;
27+ const { data } = useApiQuery (
28+ [ '/admin/users' , params ] , // queryKey에 params 포함
29+ ( ) => usersRequest ( params )
30+ ) ;
31+
32+ useEffect ( ( ) => {
33+ if ( data ) {
34+ setTableRows ( data . users ) ;
35+ }
36+ } , [ data ] )
37+
38+ const handleSearch = ( e ) => {
39+ e . preventDefault ( ) ;
40+ console . log ( "검색어:" , searchTerm )
41+ setParams ( {
42+ ...params ,
43+ page : 1 ,
44+ nickname : searchTerm . trim ( )
45+ } )
46+ }
47+
48+ const handleClearSearch = ( ) => {
49+ setParams ( {
50+ ...params ,
51+ nickname : ''
52+ } )
53+ setSearchTerm ( "" )
54+ }
55+
56+ return (
57+ < div className = "min-h-screen bg-gray-100 p-8" >
58+ < div className = "max-w-6xl mx-auto bg-white rounded-lg shadow-md border border-gray-200" >
59+ { /* 헤더 및 검색 섹션 */ }
60+ < div className = "p-6 border-b border-gray-200 flex items-center justify-between" >
61+ < h1 className = "text-xl font-bold text-gray-900" > [ 유저 관리 페이지 ]</ h1 >
62+ < form className = "flex items-center space-x-2" onSubmit = { handleSearch } >
63+ < div className = "relative w-64" >
64+ < input
65+ type = "text"
66+ placeholder = "유저 검색 ..."
67+ value = { searchTerm }
68+ onChange = { ( e ) => setSearchTerm ( e . target . value ) }
69+ className = "flex h-10 w-full rounded-md border border-input bg-background px-3 py-2 text-sm ring-offset-background file:border-0 file:bg-transparent file:text-sm file:font-medium placeholder:text-muted-foreground focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:cursor-not-allowed disabled:opacity-50 text-gray-900"
70+ />
71+ { searchTerm && (
72+ < button
73+ type = "button"
74+ className = "absolute right-1 top-1/2 -translate-y-1/2 h-6 w-6 p-0 text-gray-500 hover:bg-gray-100 rounded-md flex items-center justify-center"
75+ onClick = { handleClearSearch }
76+ >
77+ < X className = "h-4 w-4" />
78+ </ button >
79+ ) }
80+ </ div >
81+ < button
82+ type = "submit"
83+ className = "inline-flex items-center justify-center whitespace-nowrap rounded-md text-sm font-medium ring-offset-background transition-colors focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-ring focus-visible:ring-offset-2 disabled:pointer-events-none disabled:opacity-50 bg-gray-800 text-white hover:bg-gray-900 h-10 px-4 py-2"
84+ >
85+ 검색
86+ </ button >
87+ </ form >
88+ </ div >
89+ < TableBackGroundCard >
90+ < FlexibleTable initColumns = { initColumns } data = { tableRows } />
91+ { /* Pagination */ }
92+ < PaginationNavigator currentPage = { data ?. currentPage } totalPages = { data ?. totalPages }
93+ onPageChange = { ( page ) => setParams ( {
94+ ...params
95+ , page : page ,
96+ } ) } />
97+ </ TableBackGroundCard >
98+ </ div >
99+ </ div >
100+ ) ;
101+ }
102+
103+ export default UserList ;
0 commit comments