Skip to content
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
"preview": "vite preview"
},
"dependencies": {
"clsx": "^2.1.1",
"react": "^19.1.0",
"react-dom": "^19.1.0",
"react-router-dom": "^7.6.1"
Expand Down
14 changes: 11 additions & 3 deletions public/common.css
Original file line number Diff line number Diff line change
Expand Up @@ -2,18 +2,26 @@
cursor: pointer;
border: none;
white-space: nowrap;
text-decoration: none;
background: none;
text-align: center;
}

.primary-btn {
background-color: var(--color-primary);
color: var(--color-white);
}

.btn:hover {
.primary-btn:not(:disabled):hover {
background-color: var(--color-primary-dark);
}

.btn:active {
.primary-btn:active {
background-color: var(--color-primary-darker);
}

.btn .disabled {
.disabled {
cursor: default;
background-color: var(--color-disabled);
}

Expand Down
4 changes: 2 additions & 2 deletions src/App.jsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
import { BrowserRouter, Routes, Route, Navigate } from "react-router-dom";
import Nav from "./components/Nav";
import Items from "./pages/Items";
import AddItem from "./pages/AddItem";
import AddItemPage from "./pages/AddItemPage/AddItemPage";

const App = () => {
return (
Expand All @@ -10,7 +10,7 @@ const App = () => {
<Routes>
<Route path="/" element={<Navigate to="/items" replace />} />
<Route path="/items" element={<Items />} />
<Route path="/additem" element={<AddItem />} />
<Route path="/additem" element={<AddItemPage />} />
</Routes>
</BrowserRouter>
);
Expand Down
17 changes: 13 additions & 4 deletions src/api.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,13 +6,22 @@ export const getProducts = async ({
pageSize = 4,
keyword = "",
}) => {
const query = `orderBy=${orderBy}&page=${currentPage}&pageSize=${pageSize}${
keyword ? `&keyword=${keyword}` : ""
}`;
const response = await fetch(`${BASE_URL}products?${query}`);
const params = new URLSearchParams({
orderBy,
page: currentPage,
pageSize,
});

if (keyword) {
params.append("keyword", keyword);
}

const response = await fetch(`${BASE_URL}products?${params.toString()}`);

if (!response.ok) {
throw new Error("항목을 불러오는데 실패했습니다.");
}

const body = await response.json();
return body;
};
Binary file added src/assets/fonts/ROKAF-Sans-Bold.ttf
Binary file not shown.
5 changes: 5 additions & 0 deletions src/assets/icons/ic_X.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
17 changes: 17 additions & 0 deletions src/common/XButton.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import XIcon from "../assets/icons/ic_X.svg";

const XButton = ({ onClick, value = null, className = "btn" }) => {
return (
<button
style={{ height: "24px" }}
className={className}
value={value}
type="button"
onClick={onClick}
>
<img src={XIcon} alt="삭제 버튼" />
</button>
);
};

export default XButton;
8 changes: 2 additions & 6 deletions src/components/AllProductList.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,13 +4,9 @@ import PaginationNav from "./PaginationNav";
import styles from "./AllProductList.module.css";
import { useState } from "react";

const calcTotalPage = (totalCount, pageSize) =>
Math.ceil(totalCount / pageSize);

const AllProductList = ({
products,
totalCount,
pageSize,
totalPage,
currentPage,
breakpoint,
inputValue,
Expand Down Expand Up @@ -45,7 +41,7 @@ const AllProductList = ({
<PaginationNav
signalSearch={signalSearch}
onClickPage={onClickPage}
totalPage={calcTotalPage(totalCount, pageSize)}
totalPage={totalPage}
currentPage={currentPage}
breakpoint={breakpoint}
/>
Expand Down
20 changes: 15 additions & 5 deletions src/components/Nav.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,23 +14,33 @@ const Nav = () => {
alt="판다마켓 로고"
className={styles["logo-img"]}
/>
<button className={styles.logo} type="button">
<button className={`btn ${styles.logo}`} type="button">
판다마켓
</button>
</div>
<button className={`${styles.link}`} type="button">
<button className={`btn ${styles.link}`} type="button">
자유게시판
</button>
<button
className={`${styles.link} ${
styles[`${location.pathname === "/items" ? "selected" : "none"}`]
className={`btn ${styles.link} ${
styles[
`${
location.pathname === "/items" ||
location.pathname === "/additem"
? "selected"
: "none"
}`
]
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

조건문이 너무 복잡해보이네요! 리턴문은 최대한 명확하고 간결하게 유지해봅시다.

  const isMarketPage =
    location.pathname === "/items" || location.pathname === "/additem";
Suggested change
className={`btn ${styles.link} ${
styles[
`${
location.pathname === "/items" ||
location.pathname === "/additem"
? "selected"
: "none"
}`
]
className={`btn ${styles.link} ${
isMarketPage ? styles.selected : styles.none
}`}

이정도로 정리해보는건 어떨까요? :)

}`}
type="button"
>
중고마켓
</button>
</div>
<button className={`btn ${styles["login-btn"]}`} type="button">
<button
className={`btn primary-btn ${styles["login-btn"]}`}
type="button"
>
로그인
</button>
</nav>
Expand Down
4 changes: 1 addition & 3 deletions src/components/Nav.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@
margin: 0 auto;
border-bottom: 1px solid var(--color-border-grey);
gap: var(--space-sm);
z-index: 999;
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

z-index는 예상치 못한 충돌을 방지하고 일관성을 높이기위해 범주화해서 사용하는것이 좋습니다.

이런식으로 css 변수를 만들어서 하드코딩한 숫자말고 미리 정해둔 범위 안에서만 숫자를 사용해보도록할까요?

:root {
  /* 기본 레이어 */
  --z-index-base: 0;
  
  /* 콘텐츠 레이어 */
  --z-index-content: 1;
  
  /* 상호작용 요소 */
  --z-index-interactive: 10;
  
  /* 드롭다운, 툴팁 */
  --z-index-dropdown: 100;
  
  /* 모달 오버레이 */
  --z-index-overlay: 200;
  
  /* 모달 */
  --z-index-modal: 300;
  
  /* 토스트, 알림 */
  --z-index-toast: 400;
  
  /* 네비게이션 */
  --z-index-navigation: 500;
  
  /* 최상위 레이어 */
  --z-index-top: 999;
}

이렇게 범주화해보면 레이어구조를 한눈에 파악할수있다는 장점도 생기겠죠?

}

.link-container {
Expand Down Expand Up @@ -56,10 +57,7 @@
display: inline-block;
width: 128px;
height: 48px;
text-decoration: none;
color: var(--color-white);
padding: 12px 20px;
text-align: center;
border-radius: 8px;
font-weight: 500;
font-size: 16px;
Expand Down
51 changes: 7 additions & 44 deletions src/components/PaginationNav.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import { useCallback, useEffect, useState } from "react";
import ArrowButton from "./ArrowButton";
import PageButton from "./PageButton";
import styles from "./PaginationNav.module.css";
import usePagination from "./hooks/UsePagination";
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

리액트 컴포넌트를 제외하고, 커스텀훅은 파스칼케이스로 작성하실 필요 없습니다 :) 파일명을 usePagination으로 맞춰주세요!


const PaginationNav = ({
signalSearch,
Expand All @@ -10,8 +11,12 @@ const PaginationNav = ({
currentPage,
breakpoint,
}) => {
const [pageList, setPageList] = useState([[1]]);
const [pageListIndex, setPageListIndex] = useState(0);
const { pageList, pageListIndex, onMovePageList } = usePagination(
totalPage,
breakpoint,
signalSearch,
onClickPage
);
const PrevArrowButton = {
shape: "<",
direction: -1,
Expand All @@ -23,48 +28,6 @@ const PaginationNav = ({
endIndex: pageList.length - 1,
};

const resetPagination = useCallback(() => {
setPageListIndex((prev) => 0);
onClickPage((prev) => 1);
}, [onClickPage]);

const onMovePageList = (direction) => {
setPageListIndex((prev) => prev + direction);
onClickPage((prev) => pageList[pageListIndex + direction][0]);
};

const calcPageList = (totalPage) => {
if (!totalPage) {
setPageList((prev) => [[1]]);
return;
}
const wholePageList = [];
const dividedPageList = [];
let count = 0;

for (let i = 1; i <= totalPage; i++) {
if (count === 5) {
wholePageList.push([...dividedPageList]);
dividedPageList.splice(0);
count = 0;
}
dividedPageList.push(i);
count++;
if (totalPage === i) {
wholePageList.push([...dividedPageList]);
}
}
setPageList((prev) => [...wholePageList]);
};

useEffect(() => {
calcPageList(totalPage);
}, [totalPage]);

useEffect(() => {
resetPagination();
}, [signalSearch, breakpoint, resetPagination]);

return (
<div className={styles.container}>
<ArrowButton
Expand Down
4 changes: 2 additions & 2 deletions src/components/SearchBar.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ const SearchBar = ({
<div className={styles.container}>
<h3>전체 상품</h3>
<Link className={styles["btn-wrapper"]} to="/additem">
<button className={`btn ${styles["additem-btn"]}`}>
<button className={`btn primary-btn ${styles["additem-btn"]}`}>
상품 등록하기
</button>
</Link>
Expand All @@ -41,7 +41,7 @@ const SearchBar = ({
placeholder="검색할 상품을 입력해주세요"
onChange={handleChangeInputValue}
onKeyDown={handleSearch}
></input>
/>
<img
className={styles["search-icon"]}
src={searchIcon}
Expand Down
3 changes: 0 additions & 3 deletions src/components/SearchBar.module.css
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,7 @@
display: inline-block;
width: 133px;
height: 42px;
text-decoration: none;
color: var(--color-white);
padding: 12px 23px;
text-align: center;
border-radius: 8px;
font-weight: 500;
font-size: 14px;
Expand Down
54 changes: 54 additions & 0 deletions src/components/hooks/UsePagination.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
import { useCallback, useEffect, useState } from "react";

const BUTTONS_PER_PAGE = 5;

const usePagination = (totalPage, breakpoint, signalSearch, onClickPage) => {
const [pageList, setPageList] = useState([[1]]);
const [pageListIndex, setPageListIndex] = useState(0);

const resetPagination = useCallback(() => {
setPageListIndex((prev) => 0);
onClickPage((prev) => 1);
}, [onClickPage]);

const onMovePageList = (direction) => {
setPageListIndex((prev) => prev + direction);
onClickPage((prev) => pageList[pageListIndex + direction][0]);
};

const calcPageList = useCallback((totalPage) => {
if (!totalPage) {
setPageList((prev) => [[1]]);
return;
}
const wholePageList = [];
const dividedPageList = [];
let count = 0;

for (let i = 1; i <= totalPage; i++) {
if (count === BUTTONS_PER_PAGE) {
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

BUTTONS_PER_PAGE를 default value로 만들고 props로 추가한다면 좀더 로직의 재사용이 유연해지겠죠? 로직의 재사용을 위해서는 UI 관련 규칙으로부터 최대한 종속성을 제거하는편이 좋습니다! :)

wholePageList.push([...dividedPageList]);
dividedPageList.splice(0);
count = 0;
}
dividedPageList.push(i);
count++;
if (totalPage === i) {
wholePageList.push([...dividedPageList]);
}
}
setPageList((prev) => [...wholePageList]);
}, []);

useEffect(() => {
calcPageList(totalPage);
}, [totalPage, calcPageList]);

useEffect(() => {
resetPagination();
}, [signalSearch, breakpoint, resetPagination]);

return { pageList, pageListIndex, onMovePageList };
};

export default usePagination;
Loading