'use client'; import { use, useState } from 'react'; import { useQuery } from '@tanstack/react-query'; import { clsx } from 'clsx'; import { ChevronLeft, ChevronRight, LayoutGrid, List, Loader2, Search as SearchIcon } from 'lucide-react'; import { getPostsByCategory } from '@/api/posts'; import PostCard from '@/components/post/PostCard'; import PostListItem from '@/components/post/PostListItem'; import PostSearch from '@/components/post/PostSearch'; import EmptyState from '@/components/ui/EmptyState'; import Surface from '@/components/ui/Surface'; import WindowSurface from '@/components/ui/WindowSurface'; const PAGE_SIZE = 10; const isNoticeCategoryName = (categoryName: string) => { const normalizedName = categoryName.toLowerCase(); return categoryName === '공지' || normalizedName === 'notice' || normalizedName === 'announcement'; }; export default function CategoryPage({ params }: { params: Promise<{ id: string }> }) { const { id } = use(params); const categoryName = decodeURIComponent(id); const apiCategoryName = categoryName === 'uncategorized' ? '미분류' : categoryName; const isNoticeCategory = isNoticeCategoryName(apiCategoryName); const [page, setPage] = useState(0); const [keyword, setKeyword] = useState(''); const [viewMode, setViewMode] = useState<'grid' | 'list'>(() => { if (isNoticeCategory || typeof window === 'undefined') return isNoticeCategory ? 'list' : 'grid'; const savedMode = localStorage.getItem('postViewMode'); return savedMode === 'list' ? 'list' : 'grid'; }); const activeViewMode = isNoticeCategory ? 'list' : viewMode; const handleViewModeChange = (mode: 'grid' | 'list') => { setViewMode(mode); if (!isNoticeCategory) { localStorage.setItem('postViewMode', mode); } }; const handleSearch = (newKeyword: string) => { setKeyword(newKeyword); setPage(0); }; const { data: postsData, isLoading, error, isPlaceholderData } = useQuery({ queryKey: ['posts', 'category', apiCategoryName, page, keyword], queryFn: () => getPostsByCategory(apiCategoryName, page, PAGE_SIZE, keyword), placeholderData: (previousData) => previousData, }); if (isLoading || (postsData === undefined && !error)) { return (
); } if (error) { return ( 게시글을 불러오는 중 오류가 발생했습니다.
카테고리 이름을 확인해 주세요.
); } const posts = postsData?.content || []; const pagingData = postsData?.page || postsData; const totalElements = pagingData?.totalElements ?? 0; const totalPages = pagingData?.totalPages ?? 0; const isLast = pagingData?.number !== undefined ? pagingData.number + 1 >= pagingData.totalPages : (postsData?.last ?? true); const handlePrevPage = () => setPage((old) => Math.max(old - 1, 0)); const handleNextPage = () => { if (!isLast) setPage((old) => old + 1); }; return (

{apiCategoryName} 글 목록

{keyword && (
검색어 {keyword} 결과: {totalElements}
)} {posts.length === 0 ? ( ) : ( <> {activeViewMode === 'grid' ? (
{posts.map((post) => ( ))}
) : ( {posts.map((post) => ( ))} )}
페이지 {page + 1} {totalPages > 0 && `/ ${totalPages}`}
)}
); }