1+ import styled from 'styled-components' ;
2+ import { useNavigate } from 'react-router-dom' ;
3+
4+ import ChevronLeft from '@/assets/icons/chevronLeft.svg?react' ;
5+ import ChevronRight from '@/assets/icons/chevronRight.svg?react' ;
6+
7+ const BoardTable = ( {
8+ data,
9+ currentPage,
10+ setCurrentPage,
11+ totalPages,
12+ visibleColumns,
13+ loading,
14+ } ) => {
15+ const navigate = useNavigate ( ) ;
16+ const BLOCK_SIZE = 5 ; // 한 블록에 표시할 페이지 수
17+
18+ const allHeaders = Object . keys ( data [ 0 ] ?? { } ) ;
19+
20+ // 현재 페이지가 속한 블록 계산
21+ const currentBlock = Math . floor ( currentPage / BLOCK_SIZE ) ;
22+
23+ // 현재 블록의 시작/끝 페이지
24+ const blockStartPage = currentBlock * BLOCK_SIZE ;
25+ const blockEndPage = Math . min ( blockStartPage + BLOCK_SIZE - 1 , totalPages - 1 ) ;
26+
27+ // 표시할 페이지 번호 배열 생성
28+ const pageNumbers = [ ] ;
29+ for ( let i = blockStartPage ; i <= blockEndPage ; i ++ ) {
30+ pageNumbers . push ( i ) ;
31+ }
32+
33+ // 이전/다음 블록 존재 여부
34+ const hasPrevBlock = currentBlock > 0 ;
35+ const hasNextBlock = blockEndPage < totalPages - 1 ;
36+
37+ // 이전 블록의 첫 페이지로 이동
38+ const goToPrevBlock = ( ) => {
39+ if ( hasPrevBlock ) {
40+ const prevBlockStart = ( currentBlock - 1 ) * BLOCK_SIZE ;
41+ setCurrentPage ( prevBlockStart ) ;
42+ }
43+ } ;
44+
45+ // 다음 블록의 첫 페이지로 이동
46+ const goToNextBlock = ( ) => {
47+ if ( hasNextBlock ) {
48+ const nextBlockStart = ( currentBlock + 1 ) * BLOCK_SIZE ;
49+ setCurrentPage ( nextBlockStart ) ;
50+ }
51+ } ;
52+
53+ return (
54+ < Wrapper >
55+ < StyledTable >
56+ < thead >
57+ < tr >
58+ { allHeaders . map ( ( key ) =>
59+ visibleColumns . includes ( key ) || key === 'manage' ? (
60+ < th key = { key } > { data [ 0 ] [ key ] } </ th >
61+ ) : null ,
62+ ) }
63+ </ tr >
64+ </ thead >
65+ < tbody >
66+ { data . slice ( 1 ) . map ( ( row , idx ) => (
67+ < tr key = { idx } >
68+ { allHeaders . map ( ( key ) => {
69+ if ( ! visibleColumns . includes ( key ) && key !== 'manage' )
70+ return null ;
71+
72+ if ( key === 'manage' ) {
73+ return (
74+ < StyledTd key = { key } >
75+ < DetailButton onClick = { ( ) => navigate ( row . manage ) } >
76+ 상세
77+ </ DetailButton >
78+ </ StyledTd >
79+ ) ;
80+ }
81+ if ( key === 'amateurShowStatus' ) {
82+ return (
83+ < StyledTd key = { key } >
84+ { row . amateurShowStatus === 'ONGOING' && (
85+ < p className = "black-txt" > 공연중</ p >
86+ ) }
87+ { row . amateurShowStatus === 'ENDED' && (
88+ < p className = "gray-txt" > 공연 종료</ p >
89+ ) }
90+ { row . amateurShowStatus === 'YET' && (
91+ < p className = "pink-txt" > 공연 전</ p >
92+ ) }
93+ </ StyledTd >
94+ ) ;
95+ }
96+
97+ return < StyledTd key = { key } > { row [ key ] } </ StyledTd > ;
98+ } ) }
99+ </ tr >
100+ ) ) }
101+ </ tbody >
102+ </ StyledTable >
103+
104+ { /* 블록 단위 페이지네이션 */ }
105+ < Pagination >
106+ { /* 이전 블록 버튼 */ }
107+ < PageBtn
108+ onClick = { goToPrevBlock }
109+ disabled = { ! hasPrevBlock }
110+ isArrow
111+ >
112+ < ChevronLeftIcon />
113+ </ PageBtn >
114+
115+ { /* 페이지 번호들 */ }
116+ { pageNumbers . map ( ( pageNum ) => (
117+ < PageBtn
118+ key = { pageNum }
119+ onClick = { ( ) => setCurrentPage ( pageNum ) }
120+ active = { currentPage === pageNum }
121+ >
122+ { pageNum + 1 }
123+ </ PageBtn >
124+ ) ) }
125+
126+ { /* 다음 블록 버튼 */ }
127+ < PageBtn
128+ onClick = { goToNextBlock }
129+ disabled = { ! hasNextBlock }
130+ isArrow
131+ >
132+ < ChevronRightIcon />
133+ </ PageBtn >
134+ </ Pagination >
135+ </ Wrapper >
136+ ) ;
137+ } ;
138+
139+ export default BoardTable ;
140+
141+ const Wrapper = styled . div `
142+ font-family: Pretendard;
143+ ` ;
144+
145+ const StyledTable = styled . table `
146+ width: 100%;
147+ border-collapse: collapse;
148+ th,
149+ td {
150+ height: 31px;
151+ }
152+ th {
153+ border: 1px solid #000;
154+ text-align: center;
155+ font-size: ${ ( { theme } ) => theme . font . fontSize . body14 } ;
156+ font-weight: ${ ( { theme } ) => theme . font . fontWeight . extraBold } ;
157+ color: ${ ( { theme } ) => theme . colors . grayMain } ;
158+ }
159+ td {
160+ border: 1px solid #000;
161+ text-align: center;
162+ font-size: ${ ( { theme } ) => theme . font . fontSize . body14 } ;
163+ font-weight: ${ ( { theme } ) => theme . font . fontWeight . bold } ;
164+ color: ${ ( { theme } ) => theme . colors . grayMain } ;
165+ }
166+ ` ;
167+
168+ const StyledTd = styled . td `
169+ .black-txt {
170+ color: ${ ( { theme } ) => theme . colors . grayMain } ;
171+ }
172+ .gray-txt {
173+ color: ${ ( { theme } ) => theme . colors . gray400 } ;
174+ }
175+ .pink-txt {
176+ color: ${ ( { theme } ) => theme . colors . pink600 } ;
177+ }
178+ ` ;
179+
180+ const DetailButton = styled . button `
181+ width: 39px;
182+ height: 20px;
183+ font-size: 10px;
184+ border: none;
185+ background-color: #d9d9d9;
186+ color: #555;
187+ cursor: pointer;
188+
189+ &:hover {
190+ background-color: #bbb;
191+ }
192+ ` ;
193+
194+ const Pagination = styled . div `
195+ margin-top: 16px;
196+ display: flex;
197+ align-items: center;
198+ justify-content: center;
199+ gap: 8px;
200+ ` ;
201+
202+ const PageBtn = styled . button `
203+ padding: ${ ( { isArrow } ) => ( isArrow ? '6px 12px' : '6px 10px' ) } ;
204+ border-radius: 4px;
205+ border: none;
206+ font-size: ${ ( { theme, active } ) =>
207+ active ? theme . font . fontSize . title16 : theme . font . fontSize . body14 } ;
208+ font-weight: ${ ( { active } ) => ( active ? '700' : '400' ) } ;
209+ color: ${ ( { active, disabled } ) =>
210+ disabled ? '#ccc' : active ? '#000' : '#989898' } ;
211+ cursor: ${ ( { disabled } ) => ( disabled ? 'default' : 'pointer' ) } ;
212+ transition: all 0.2s;
213+
214+ &:hover:not(:disabled) {
215+ background-color: ${ ( { active, theme } ) =>
216+ active ? theme . colors . pink100 || '#FFF1EF' : '#f8f8f8' } ;
217+ }
218+
219+ &:disabled {
220+ opacity: 0.3;
221+ }
222+ ` ;
223+
224+ const ChevronLeftIcon = styled ( ChevronLeft ) `
225+ color: ${ ( { theme } ) => theme . colors . gray400 } ;
226+ height: 16px;
227+ width: 16px;
228+ ` ;
229+
230+ const ChevronRightIcon = styled ( ChevronRight ) `
231+ color: ${ ( { theme } ) => theme . colors . gray400 } ;
232+ height: 16px;
233+ width: 16px;
234+ ` ;
0 commit comments