'use client'; import { useEffect, useMemo, useState } from 'react'; import { useRouter } from 'next/navigation'; import PaperClipSvg from '../svgs/paperclipsvg'; import ChevronDownSvg from '../svgs/chevrondownsvg'; import apiService from '../lib/apiService'; import type { Notice } from '../admin/notices/mockData'; export default function NoticesPage() { const router = useRouter(); const ITEMS_PER_PAGE = 10; const [currentPage, setCurrentPage] = useState(1); const [notices, setNotices] = useState([]); const [loading, setLoading] = useState(true); const [totalCount, setTotalCount] = useState(0); // 공지사항 리스트 가져오기 useEffect(() => { let isMounted = true; async function fetchNotices() { try { setLoading(true); const response = await apiService.getNotices(); if (response.status !== 200 || !response.data) { return; } // API 응답이 배열이 아닌 경우 처리 (예: { items: [...] } 형태) let noticesArray: any[] = []; let total = 0; if (Array.isArray(response.data)) { noticesArray = response.data; total = response.data.length; } else if (response.data && typeof response.data === 'object') { noticesArray = response.data.items || response.data.notices || response.data.data || response.data.list || []; total = response.data.total !== undefined ? response.data.total : response.data.totalCount !== undefined ? response.data.totalCount : response.data.count !== undefined ? response.data.count : noticesArray.length; } // 날짜를 yyyy-mm-dd 형식으로 포맷팅 const formatDate = (dateString: string): string => { if (!dateString) return ''; try { const date = new Date(dateString); if (isNaN(date.getTime())) { // 이미 yyyy-mm-dd 형식인 경우 그대로 반환 if (/^\d{4}-\d{2}-\d{2}$/.test(dateString)) { return dateString; } return dateString; } const year = date.getFullYear(); const month = String(date.getMonth() + 1).padStart(2, '0'); const day = String(date.getDate()).padStart(2, '0'); return `${year}-${month}-${day}`; } catch { return dateString; } }; // API 응답 데이터를 Notice 형식으로 변환 const transformedNotices: Notice[] = noticesArray.map((notice: any) => ({ id: notice.id || notice.noticeId || 0, title: notice.title || '', date: formatDate(notice.date || notice.createdAt || notice.createdDate || new Date().toISOString().split('T')[0]), views: notice.views || notice.viewCount || 0, writer: notice.writer || notice.author || notice.createdBy || '관리자', content: notice.content ? (Array.isArray(notice.content) ? notice.content : [notice.content]) : undefined, hasAttachment: notice.hasAttachment || notice.attachment || false, })); if (!isMounted) return; // 날짜 내림차순 정렬 (최신 날짜가 먼저) const sortedNotices = [...transformedNotices].sort((a, b) => b.date.localeCompare(a.date)); setNotices(sortedNotices); setTotalCount(total || sortedNotices.length); } catch (error) { console.error('공지사항 리스트 조회 오류:', error); } finally { if (isMounted) { setLoading(false); } } } fetchNotices(); return () => { isMounted = false; }; }, []); const totalPages = Math.ceil(totalCount / ITEMS_PER_PAGE); const pagedNotices = useMemo( () => notices.slice((currentPage - 1) * ITEMS_PER_PAGE, currentPage * ITEMS_PER_PAGE), [notices, currentPage] ); // 페이지네이션: 10개씩 표시 const pageGroup = Math.floor((currentPage - 1) / 10); const startPage = pageGroup * 10 + 1; const endPage = Math.min(startPage + 9, totalPages); const visiblePages = Array.from({ length: endPage - startPage + 1 }, (_, i) => startPage + i); return (
{/* 헤더 영역 */}

공지사항

{/* 본문 영역 */}
{/* 총 건수 */}

{totalCount}

{loading ? (

로딩 중...

) : ( <> {/* 표 */}
{/* 헤더 */}
번호
제목
게시일
조회수
작성자
{/* 바디 */}
{pagedNotices.length === 0 ? (

공지사항이 없습니다.

) : ( pagedNotices.map((notice, index) => { // 번호는 전체 목록에서의 순서 (최신이 1번) const noticeNumber = totalCount - ((currentPage - 1) * ITEMS_PER_PAGE + index); return (
router.push(`/notices/${notice.id}`)} onKeyDown={(e) => { if (e.key === 'Enter' || e.key === ' ') { e.preventDefault(); router.push(`/notices/${notice.id}`); } }} className="grid grid-cols-[57px_1fr_140px_140px_140px] h-[48px] text-[15px] font-medium text-[#1B2027] border-t border-[#DEE1E6] hover:bg-[rgba(236,240,255,0.5)] cursor-pointer" >
{noticeNumber}
{notice.title} {notice.hasAttachment && ( )}
{notice.date}
{notice.views.toLocaleString()}
{notice.writer}
); }) )}
{/* 페이지네이션 - 10개 초과일 때만 표시 */} {totalCount > ITEMS_PER_PAGE && (
{/* First (맨 앞으로) */} {/* Prev */} {/* Numbers */} {visiblePages.map((n) => { const active = n === currentPage; return ( ); })} {/* Next */} {/* Last (맨 뒤로) */}
)} )}
); }