diff --git a/.gitignore b/.gitignore
index 4d29575de..3a894327c 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,5 +1,8 @@
# See https://help.github.com/articles/ignoring-files/ for more about ignoring files.
+#file
+visualwind.wrapper.tsx
+
# dependencies
/node_modules
/.pnp
diff --git a/src/App.jsx b/src/App.jsx
index 8cd05c49f..d41047767 100644
--- a/src/App.jsx
+++ b/src/App.jsx
@@ -19,7 +19,10 @@ function App() {
} /> */}
} />
} />
- } />
+
+ } />
+ } />
+
} />
diff --git a/src/assets/images/icons/ic_X.svg b/src/assets/images/icons/ic_X.svg
new file mode 100644
index 000000000..522eca44f
--- /dev/null
+++ b/src/assets/images/icons/ic_X.svg
@@ -0,0 +1,5 @@
+
diff --git a/src/assets/images/icons/ic_union.svg b/src/assets/images/icons/ic_union.svg
new file mode 100644
index 000000000..f4ada2f05
--- /dev/null
+++ b/src/assets/images/icons/ic_union.svg
@@ -0,0 +1,3 @@
+
diff --git a/src/components/items/BestItems/BestItems.jsx b/src/components/items/BestItems/BestItems.jsx
index 5c1b75bd3..081d270f1 100644
--- a/src/components/items/BestItems/BestItems.jsx
+++ b/src/components/items/BestItems/BestItems.jsx
@@ -22,17 +22,24 @@ function BestItems() {
const [page, setPage] = useState(1);
const [pageSize, setPageSize] = useState(4);
const [keyword, setKeyword] = useState('');
+ // 에러
+ const [fetchingError, setfetchingError] = useState(null);
const fetchItemList = async ({ order, page, pageSize, keyword }) => {
- let products = await getProducts({ order, page, pageSize, keyword });
- setItemList(products.list);
+ try {
+ setfetchingError(null);
+ const products = await getProducts({ order, page, pageSize, keyword });
+ setItemList(products.list);
+ } catch (err) {
+ setItemList([]);
+ setfetchingError(err);
+ }
+ };
+ const handleResize = () => {
+ setPageSize(getPageSize());
};
useEffect(() => {
- const handleResize = () => {
- setPageSize(getPageSize());
- };
-
window.addEventListener('resize', handleResize);
fetchItemList({ order, page, pageSize, keyword });
@@ -47,6 +54,7 @@ function BestItems() {
베스트 상품
+ {fetchingError && fetchingError.message}
{itemList?.map((item) => (
))}
diff --git a/src/components/items/PaginationBar/PaginatinoBar.css b/src/components/items/PaginationBar/PaginatinoBar.css
new file mode 100644
index 000000000..a2cb0298f
--- /dev/null
+++ b/src/components/items/PaginationBar/PaginatinoBar.css
@@ -0,0 +1,33 @@
+.pagination-bar {
+ display: flex;
+ align-items: center;
+ justify-content: center;
+}
+
+.btn-pagination {
+ border: 1px solid #e5e7eb;
+ border-radius: 50%;
+ width: 40px;
+ height: 40px;
+ color: #6b7280;
+ font-weight: 600;
+ font-size: 16px;
+ display: flex;
+ align-items: center;
+ justify-content: center;
+ margin-right: 20px;
+}
+
+.btn-pagination:last-child {
+ margin-right: 0;
+}
+
+.btn-pagination:disabled {
+ cursor: default;
+ opacity: 0.5;
+}
+
+.btn-pagination.active {
+ background-color: var(--blue);
+ color: #fff;
+}
diff --git a/src/components/items/PaginationBar/PaginationBar.jsx b/src/components/items/PaginationBar/PaginationBar.jsx
new file mode 100644
index 000000000..4060b546a
--- /dev/null
+++ b/src/components/items/PaginationBar/PaginationBar.jsx
@@ -0,0 +1,55 @@
+import React from 'react';
+import './PaginatinoBar.css';
+import { ReactComponent as IconArrowLeft } from '../../../assets/images/icons/arrow_left.svg';
+import { ReactComponent as IconArrowRight } from '../../../assets/images/icons/arrow_right.svg';
+
+function PaginationBar({ totalPageNum, activePageNum, onPageChange }) {
+ const maxVisiblePages = 5;
+ let startPage;
+
+ if (totalPageNum <= maxVisiblePages) {
+ startPage = 1;
+ } else {
+ startPage = Math.max(activePageNum - Math.floor(maxVisiblePages / 2), 1);
+ startPage = Math.min(startPage, totalPageNum - maxVisiblePages + 1);
+ }
+
+ const pages = Array.from(
+ { length: Math.min(maxVisiblePages, totalPageNum - startPage + 1) },
+ (_, i) => startPage + i
+ );
+ return (
+ <>
+
+
+ {/* 반복 */}
+ {pages.map((page) => (
+
+ ))}
+
+
+ >
+ );
+}
+
+export default PaginationBar;
diff --git a/src/components/items/SailItems/SailItems.css b/src/components/items/SellingItems/SellingItems.css
similarity index 100%
rename from src/components/items/SailItems/SailItems.css
rename to src/components/items/SellingItems/SellingItems.css
diff --git a/src/components/items/SailItems/SailItems.jsx b/src/components/items/SellingItems/SellingItems.jsx
similarity index 67%
rename from src/components/items/SailItems/SailItems.jsx
rename to src/components/items/SellingItems/SellingItems.jsx
index 4582f9b6e..4b063a2bb 100644
--- a/src/components/items/SailItems/SailItems.jsx
+++ b/src/components/items/SellingItems/SellingItems.jsx
@@ -1,9 +1,10 @@
-import './SailItems.css';
import { ReactComponent as IconSearch } from '../../../assets/images/icons/ic_search.svg';
import { ReactComponent as IconSort } from '../../../assets/images/icons/ic_sort.svg';
import { useEffect, useState } from 'react';
import { getProducts } from '../../../pages/api/Items';
import Item from '../Item/Item';
+import PaginationBar from '../PaginationBar/PaginationBar';
+import './SellingItems.css';
const getPageSize = () => {
const width = window.innerWidth;
@@ -16,7 +17,7 @@ const getPageSize = () => {
}
};
-function SailItems() {
+function SellingItems() {
// 상품
const [itemList, setItemList] = useState([]);
// 쿼리
@@ -26,7 +27,14 @@ function SailItems() {
const [keyword, setKeyword] = useState('');
// 검색
const [isDropdownVisible, setIsDropdownVisible] = useState(false);
+ // 페이지네이션
+ const [totalPageNum, setTotalPageNum] = useState();
+ // 에러
+ const [fetchingError, setfetchingError] = useState(null);
+ const handlePageChange = (pageNumber) => {
+ setPage(pageNumber);
+ };
const handleClickDropdown = () => {
setIsDropdownVisible(!isDropdownVisible);
};
@@ -42,8 +50,16 @@ function SailItems() {
};
const fetchItemList = async ({ order, page, pageSize, keyword }) => {
- let products = await getProducts({ order, page, pageSize, keyword });
- setItemList(products.list);
+ try {
+ setfetchingError(null);
+ const products = await getProducts({ order, page, pageSize, keyword });
+ setItemList(products.list);
+ setTotalPageNum(Math.ceil(products.totalCount / pageSize));
+ } catch (err) {
+ setItemList([]);
+ setTotalPageNum(0);
+ setfetchingError(err);
+ }
};
useEffect(() => {
@@ -60,15 +76,15 @@ function SailItems() {
return (
<>
-
+
{/* 판매 중인 상품 헤더 */}
-
-
-
판매 중인 상품
+
+
-
{/* 판매 중인 상품 목록 */}
-
+ {fetchingError && (
+
+ {fetchingError.message}
+
+ )}
+
{itemList?.map((item) => (
-
+
))}
+
>
);
}
-export default SailItems;
+export default SellingItems;
diff --git a/src/components/navigationBar/NavigationBar.css b/src/components/navigationBar/NavigationBar.css
index d4f2845ca..e43bbd72d 100644
--- a/src/components/navigationBar/NavigationBar.css
+++ b/src/components/navigationBar/NavigationBar.css
@@ -12,33 +12,37 @@
border-bottom: 1px solid #dfdfdf;
}
-.navbarLeft {
+.navbar-left {
display: flex;
align-items: center;
}
-.navbarHomeLogo {
+.navbar-home-logo {
width: 153px;
}
-.navbarMenu {
+.navbar-menu {
margin: 0 15px;
text-decoration: none;
}
-.navbarMenu ol {
+.navbar-menu ol {
list-style-type: none;
padding-left: 0;
}
-.navbarMenuItem {
+.navbar-menu-item {
display: inline-block;
margin: 10px;
font-size: 18px;
font-weight: bold;
}
-.navbarMenuItem.active {
+.navbar-menu-item.active {
+ color: var(--blue);
+}
+
+.nav-bar-menu-link.active {
color: var(--blue);
}
diff --git a/src/components/navigationBar/NavigationBar.jsx b/src/components/navigationBar/NavigationBar.jsx
index ccbd95479..c45fe3d5f 100644
--- a/src/components/navigationBar/NavigationBar.jsx
+++ b/src/components/navigationBar/NavigationBar.jsx
@@ -1,29 +1,46 @@
-import { useEffect, useState } from 'react';
+import { NavLink } from 'react-router-dom';
import imgPandaMarketLogo from '../../assets/images/logo/panda-market-logo.png';
import './NavigationBar.css';
function NavigationBar() {
return (
-
+
-