import { useState, useEffect, useCallback } from 'react'; import { useAuthStore } from '@common/store/authStore'; import { fetchBoardPosts, type BoardPostItem } from '../services/boardApi'; import Badge from '@common/components/ui/Badge'; // 카테고리 코드 ↔ 표시명 매핑 const CATEGORY_MAP: Record = { NOTICE: '공지사항', DATA: '자료실', QNA: 'Q&A', MANUAL: '해경매뉴얼', }; const CATEGORY_FILTER: { label: string; code: string | null }[] = [ { label: '전체', code: null }, { label: '공지사항', code: 'NOTICE' }, { label: '자료실', code: 'DATA' }, { label: 'Q&A', code: 'QNA' }, ]; const PAGE_SIZE = 20; interface BoardListTableProps { onPostClick: (id: number) => void; onWriteClick: () => void; } export function BoardListTable({ onPostClick, onWriteClick }: BoardListTableProps) { const hasPermission = useAuthStore((s) => s.hasPermission); const [posts, setPosts] = useState([]); const [totalCount, setTotalCount] = useState(0); const [page, setPage] = useState(1); const [selectedCategory, setSelectedCategory] = useState(null); const [searchTerm, setSearchTerm] = useState(''); const [searchInput, setSearchInput] = useState(''); const [loading, setLoading] = useState(false); const totalPages = Math.max(1, Math.ceil(totalCount / PAGE_SIZE)); // 카테고리별 서브리소스 권한 확인 (전체 선택 시 board CREATE) const canWrite = selectedCategory ? hasPermission(`board:${selectedCategory.toLowerCase()}`, 'CREATE') : hasPermission('board', 'CREATE'); const loadPosts = useCallback(async () => { setLoading(true); try { const result = await fetchBoardPosts({ categoryCd: selectedCategory || undefined, search: searchTerm || undefined, page, size: PAGE_SIZE, }); setPosts(result.items); setTotalCount(result.totalCount); } catch { setPosts([]); setTotalCount(0); } finally { setLoading(false); } }, [selectedCategory, searchTerm, page]); useEffect(() => { loadPosts(); }, [loadPosts]); const handleCategoryChange = (code: string | null) => { setSelectedCategory(code); setPage(1); }; const handleSearch = () => { setSearchTerm(searchInput); setPage(1); }; const handleSearchKeyDown = (e: React.KeyboardEvent) => { if (e.key === 'Enter') handleSearch(); }; const formatDate = (dtm: string) => { return new Date(dtm).toLocaleDateString('ko-KR', { year: 'numeric', month: '2-digit', day: '2-digit', }); }; return (
{/* Header with Search and Write Button */}
{CATEGORY_FILTER.map((cat) => ( ))}
setSearchInput(e.target.value)} onKeyDown={handleSearchKeyDown} className="wing-input-search" /> {canWrite && ( )}
{/* Board List Table */}
{loading ? (

불러오는 중...

) : ( <> {posts.map((post) => ( onPostClick(post.sn)} className="wing-table-row" > ))}
번호 분류 제목 작성자 작성일 조회수
{post.pinnedYn === 'Y' ? ( 공지 ) : ( post.sn )} {CATEGORY_MAP[post.categoryCd] || post.categoryCd} {post.title} {post.authorName} {formatDate(post.regDtm)} {post.viewCnt}
{posts.length === 0 && (

검색 결과가 없습니다.

)} )}
{/* Pagination */} {totalPages > 1 && (
{Array.from({ length: totalPages }, (_, i) => i + 1).map((p) => ( ))}
)}
); }