diff --git a/src/components/atoms/Pagination/Pagination.tsx b/src/components/atoms/Pagination/Pagination.tsx index dd0c2dc..dd2c42b 100644 --- a/src/components/atoms/Pagination/Pagination.tsx +++ b/src/components/atoms/Pagination/Pagination.tsx @@ -2,25 +2,40 @@ import React from 'react'; import styles from './Pagination.module.scss'; interface PaginationProps { - totalPages: number; + totalItemsLength: number; activePage: number; onPageClick: (page: number) => void; + size?: number; + totalPages: number; } -const Pagination: React.FC = ({ totalPages, activePage, onPageClick }) => { +const Pagination: React.FC = ({ + totalItemsLength, + activePage, + onPageClick, + size = 9, + totalPages, +}) => { + const pages = totalPages ?? Math.ceil(totalItemsLength / size); + + if (pages <= 1) return null; + return (
- {Array.from({ length: totalPages }, (_, index) => ( - - onPageClick(index + 1)} - > - {index + 1} - - {index < totalPages - 1 && |} - - ))} + {Array.from({ length: pages }, (_, index) => { + const pageNumber = index + 1; + return ( + + onPageClick(pageNumber)} + > + {pageNumber} + + {pageNumber < pages && |} + + ); + })}
); }; diff --git a/src/pages/ListPageCategory/ListPageCategory.tsx b/src/pages/ListPageCategory/ListPageCategory.tsx index 4b862c2..a61cb7c 100644 --- a/src/pages/ListPageCategory/ListPageCategory.tsx +++ b/src/pages/ListPageCategory/ListPageCategory.tsx @@ -1,29 +1,32 @@ -import styles from '@/pages/ListPageCategory/ListPageCategory.module.scss' -import CategoryTab from '@/components/common/CategoryTabs/CategoryTabs' -import CardList from '@/components/common/CardList/CardList/CardList' -import Toggle from '@/components/atoms/Toggle/Toggle' -import ListPageDropdown from '@/components/atoms/ListPageDropdown/ListPageDropdown' -import Pagination from '@/components/atoms/Pagination/Pagination' -import React, { useCallback, useEffect, useState } from 'react' -import { useNavigate, useParams, useSearchParams } from 'react-router-dom' -import { getCategoryPostList } from '@/api/hooks/card/cardApi' -import { CardData } from '@/api/hooks/card/types' -import Container from '@/components/atoms/Container/Container' +import styles from '@/pages/ListPageCategory/ListPageCategory.module.scss'; +import CategoryTab from '@/components/common/CategoryTabs/CategoryTabs'; +import CardList from '@/components/common/CardList/CardList/CardList'; +import Toggle from '@/components/atoms/Toggle/Toggle'; +import ListPageDropdown from '@/components/atoms/ListPageDropdown/ListPageDropdown'; +import Pagination from '@/components/atoms/Pagination/Pagination'; +import React, { useCallback, useEffect, useState } from 'react'; +import { useNavigate, useParams, useSearchParams } from 'react-router-dom'; +import { getCategoryPostList } from '@/api/hooks/card/cardApi'; +import { CardData, PageInfo } from '@/api/hooks/card/types'; +import Container from '@/components/atoms/Container/Container'; const ListPageCategory: React.FC = () => { - const { category } = useParams<{ category: string }>() - const [searchParams, setSearchParams] = useSearchParams() - const navigate = useNavigate() - const [isChecked, setIsChecked] = useState(searchParams.get('filter') === 'true') - const [activePage, setActivePage] = useState(Number(searchParams.get('page')) || 1) - const [selected, setSelected] = useState(searchParams.get('sort') || '최신 순') - const [selectedCategory, setSelectedCategory] = useState(category || null) - const totalPages = 8 - const [isOpen, setIsOpen] = useState(false) - const [posts, setPosts] = useState([]) - const [loading, setLoading] = useState(false) - - const options = ['최신 순', '약속 시간 임박 순', '낮은 가격 순', '남은 인원 적은 순'] + const { category } = useParams<{ category: string }>(); + const [searchParams, setSearchParams] = useSearchParams(); + const navigate = useNavigate(); + const [isChecked, setIsChecked] = useState(searchParams.get('filter') === 'true'); + const [activePage, setActivePage] = useState(Number(searchParams.get('page')) || 1); + const [selected, setSelected] = useState(searchParams.get('sort') || '최신 순'); + const [selectedCategory, setSelectedCategory] = useState(category || null); + const [isOpen, setIsOpen] = useState(false); + const [posts, setPosts] = useState([]); + const [loading, setLoading] = useState(false); + const [pageInfo, setPageInfo] = useState({ totalItemsLength: 0, currentPage: 1, size: 9 }); + + const [totalPages, setTotalPages] = useState(0); + const [initialTotalItems, setInitialTotalItems] = useState(0); // ✅ 최초 totalItemsLength 저장 + + const options = ['최신 순', '약속 시간 임박 순', '낮은 가격 순', '남은 인원 적은 순']; const categoryMap: Record = { etc: 1, @@ -31,7 +34,7 @@ const ListPageCategory: React.FC = () => { sauce: 3, powder: 4, jam: 5, - } + }; const categoryLabelMap: Record = { liquid: '액체류', @@ -39,27 +42,27 @@ const ListPageCategory: React.FC = () => { powder: '가루류', jam: '잼류', etc: '기타', - } + }; const sortByMap: Record = { '최신 순': 'latest', '약속 시간 임박 순': 'soonest', '낮은 가격 순': 'lowestPrice', '남은 인원 적은 순': 'lowestRemain', - } + }; useEffect(() => { setSearchParams({ sort: selected, filter: String(isChecked), page: String(activePage), - }) - }, [selected, isChecked, activePage, setSearchParams]) + }); + }, [selected, isChecked, activePage, setSearchParams]); const fetchPosts = useCallback(async () => { - const categoryId = selectedCategory ? categoryMap[selectedCategory] : 0 - const sortBy = sortByMap[selected] || 'latest' - setLoading(true) + const categoryId = selectedCategory ? categoryMap[selectedCategory] : 0; + const sortBy = sortByMap[selected] || 'latest'; + setLoading(true); try { const response = await getCategoryPostList({ categoryId: categoryId ?? undefined, @@ -67,98 +70,93 @@ const ListPageCategory: React.FC = () => { page: activePage, size: 9, isMinimumPeopleMet: isChecked, - }) - setLoading(false) - setPosts(response.items) + }); + setLoading(false); + setPosts(response.items); + setPageInfo(response.pageInfoDto); } catch (error) { - console.error('Error fetching posts:', error) + console.error('Error fetching posts:', error); } - }, [selectedCategory, selected, activePage, isChecked]) + }, [selectedCategory, selected, activePage, isChecked]); useEffect(() => { - fetchPosts() - }, [fetchPosts]) + fetchPosts(); + }, [fetchPosts]); + useEffect(() => { - console.log('Fetched posts:', posts) - }, [posts]) + console.log('Fetched posts:', posts); + }, [posts]); + + // ✅ totalPages를 카테고리 변경 시 초기화, fetchPosts 실행 시 변경되지 않도록 함 + useEffect(() => { + if (pageInfo.totalItemsLength > 0) { + if (initialTotalItems === 0 || selectedCategory) { + setInitialTotalItems(pageInfo.totalItemsLength); + setTotalPages(Math.ceil(pageInfo.totalItemsLength / pageInfo.size)); + } + } + }, [selectedCategory, pageInfo.totalItemsLength, pageInfo.size]); + + // ✅ 카테고리가 변경되면 activePage를 1로 초기화 + useEffect(() => { + setActivePage(1); + }, [selectedCategory]); const handleToggle = () => { - const newFilterState = !isChecked - setIsChecked(newFilterState) + const newFilterState = !isChecked; + setIsChecked(newFilterState); setSearchParams({ sort: selected, filter: String(newFilterState), page: String(activePage), - }) - } + }); + }; const toggleDropdown = () => { - setIsOpen(!isOpen) - } + setIsOpen(!isOpen); + }; const handleOptionClick = (option: string) => { - setSelected(option) - setIsOpen(false) + setSelected(option); + setIsOpen(false); setSearchParams({ sort: option, filter: String(isChecked), page: String(activePage), - }) - } + }); + }; const handlePageClick = (page: number) => { - setActivePage(page) - console.log(`선택된 페이지: ${page}`) + setActivePage(page); + setSearchParams({ sort: selected, filter: String(isChecked), page: String(page), - }) - } + }); + + navigate( + selectedCategory + ? `/list/category/${selectedCategory}?sort=${selected}&filter=${isChecked}&page=${page}` + : `/list?sort=${selected}&filter=${isChecked}&page=${page}`, + { replace: true } + ); + }; const handleCategorySelect = (categoryName: string) => { if (selectedCategory === categoryName) { - setSelectedCategory(null) - } else { - setSelectedCategory(categoryName) - } - } - - useEffect(() => { - if (!selectedCategory || selectedCategory === '0') { - navigate(`/list?sort=${selected}&filter=${isChecked}&page=${activePage}`, { replace: true }) + setSelectedCategory(null); } else { - navigate( - `/list/category/${selectedCategory}?sort=${selected}&filter=${isChecked}&page=${activePage}`, - { replace: true }, - ) + setSelectedCategory(categoryName); } - }, [selectedCategory, selected, isChecked, activePage, navigate]) - - useEffect(() => { - const sort = searchParams.get('sort') || '최신 순' - const filter = searchParams.get('filter') === 'true' - const page = Number(searchParams.get('page')) || 1 - - setSelected(sort) - setIsChecked(filter) - setActivePage(page) - }, [category, searchParams]) - - const displayedCategory = selectedCategory - ? categoryLabelMap[selectedCategory] || selectedCategory - : '' + }; return (
카테고리 선택하기
- +
@@ -166,8 +164,7 @@ const ListPageCategory: React.FC = () => { {selectedCategory ? ( <> - '{displayedCategory}' 소분 게시글 - 목록 + '{categoryLabelMap[selectedCategory]}' 소분 게시글 목록 ) : ( '양념장 소분 게시글 목록' @@ -176,24 +173,16 @@ const ListPageCategory: React.FC = () => {
- +
- {loading && ( - - Loading... - - )} + + {loading && Loading...} - + +
- ) -} + ); +}; -export { ListPageCategory } +export { ListPageCategory };