Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[정성현] sprint7 #104

Merged
Show file tree
Hide file tree
Changes from all 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
2 changes: 2 additions & 0 deletions src/Router.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,13 +8,15 @@ import {

import Layout from "./components/layout/Layout.js";
import ItemListPage from "./pages/itemListPage/ItemListPage.js";
import AddItemPage from "./pages/addItemPage/AddItemPage.js";

const router = createBrowserRouter(
createRoutesFromElements(
<>
<Route element={<Layout />}>
<Route index element={<h1>홈페이지</h1>} />
<Route path="items" element={<ItemListPage />} />
<Route path="additem" element={<AddItemPage />} />
</Route>
<Route element={<Outlet />}>
<Route path="login" element={<h1>로그인</h1>} />
Expand Down
10 changes: 7 additions & 3 deletions src/apis/apis.js
Original file line number Diff line number Diff line change
@@ -1,5 +1,10 @@
const baseUrl = "https://panda-market-api.vercel.app/";

async function processResponse(response) {
if (!response.ok) throw Error(`${response.status}: ${response.statusText}`);
return await response.json();
}

export async function getProducts({
page = 1,
pageSize = 10,
Expand All @@ -12,7 +17,6 @@ export async function getProducts({
url.search = new URLSearchParams(paramObj);

const response = await fetch(url);
if (!response.ok) throw Error(`${response.status}: ${response.statusText}`);
const body = await response.json();
return body;

return processResponse(response);
}
14 changes: 7 additions & 7 deletions src/components/Dropdown.css
Original file line number Diff line number Diff line change
@@ -1,13 +1,13 @@
.orderSelect {
.dropdown {
position: relative;
}
@media (max-width: 767px) {
.orderSelect {
.dropdown {
order: 2;
}
}

.orderSelect__select {
.dropdown__select {
width: 128px;
height: 42px;
padding-left: 20px;
Expand All @@ -17,15 +17,15 @@
text-align: left;
}
@media (max-width: 767px) {
.orderSelect__select {
.dropdown__select {
order: 2;
width: 42px;
background: url("../assets/sort.svg") no-repeat center center;
font-size: 0;
}
}

.orderSelect__optionList {
.dropdown__optionList {
position: absolute;
top: 50px;
right: 0px;
Expand All @@ -34,11 +34,11 @@
background-color: white;
}

.orderSelect__optionListItem:not(:last-child) {
.dropdown__optionListItem:not(:last-child) {
border-bottom: 1px solid var(--gray-200);
}

.orderSelect__option {
.dropdown__option {
width: 128px;
height: 42px;
}
52 changes: 24 additions & 28 deletions src/components/Dropdown.js
Original file line number Diff line number Diff line change
@@ -1,54 +1,50 @@
import { useState, useEffect } from "react";
import "./Dropdown.css";

export default function Dropdown({ setParamObj }) {
export default function Dropdown({ onSelect, children }) {
const [isActive, setIsActive] = useState(false);
const [value, setValue] = useState("recent");
const [value, setValue] = useState(children[0].props.value);

const handleSelectClick = () => {
setIsActive((prev) => !prev);
};
const handleSelectBlur = (e) => {
if (e.relatedTarget?.className === "orderSelect__option") return;
if (e.relatedTarget?.className === "dropdown__option") return;
setIsActive(false);
};
const handleRecentClick = () => {
setValue("recent");
setIsActive(false);
};
const handleFavoriteClick = () => {
setValue("favorite");
const handleOptionClick = (e) => {
setValue(e.target.value);
setIsActive(false);
};

useEffect(() => {
setParamObj((prevObj) => ({ ...prevObj, page: 1, orderBy: value }));
}, [setParamObj, value]);
onSelect(value);
}, [onSelect, value]);
Comment on lines +21 to +22
Copy link
Collaborator

Choose a reason for hiding this comment

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

P1:
Dropdown 컴포넌트 내부 state인 value가 바뀌었을 때 이를 onSelect 함수로 전달하는 것보다
handleOptionClick 함수에서 onSelect(value)로 전달하는게 더 좋을 것 같아요.


return (
<div className="orderSelect">
<div className="dropdown">
<button
className="orderSelect__select"
className="dropdown__select"
type="button"
onClick={handleSelectClick}
onBlur={handleSelectBlur}
>
{value === "recent" ? "최신순" : "좋아요순"}
{children.find((child) => value === child.props.value).props.children}
Copy link
Collaborator

Choose a reason for hiding this comment

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

P2:
value를 바로 props로 받으시면 더 좋을 것 같아요.

</button>
{isActive && (
<ul className="orderSelect__optionList">
<li className="orderSelect__optionListItem">
<button className="orderSelect__option" onClick={handleRecentClick}>
최신순
</button>
</li>
<li className="orderSelect__optionListItem">
<button
className="orderSelect__option"
onClick={handleFavoriteClick}
>
좋아요순
</button>
</li>
<ul className="dropdown__optionList">
{children.map((child) => (
<li key={child.props.value} className="dropdown__optionListItem">
<button
className="dropdown__option"
type="button"
onClick={handleOptionClick}
value={child.props.value}
>
{child.props.children}
</button>
</li>
))}
</ul>
)}
</div>
Expand Down
Original file line number Diff line number Diff line change
@@ -1,16 +1,16 @@
.pagenationBar {
.paginationBar {
display: flex;
flex-direction: column;
align-items: center;
}

.pagenationBar__wrapper {
.paginationBar__wrapper {
display: flex;
align-items: center;
gap: 4px;
}

.pagenationBar__button {
.paginationBar__button {
display: flex;
align-items: center;
justify-content: center;
Expand All @@ -22,7 +22,7 @@
color: var(--gray-600);
}

.pagenationBar__button--current {
.paginationBar__button--current {
background-color: var(--blue-100);
border: 1px solid var(--blue-100);
border-radius: 100%;
Expand Down
48 changes: 23 additions & 25 deletions src/components/PagenationBar.js → src/components/PaginationBar.js
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ import prevPageIcon from "../assets/arrow_left_active.svg";
import inPrevPageIcon from "../assets/arrow_left_inactive.svg";
import nextPageIcon from "../assets/arrow_right_active.svg";
import inNextPageIcon from "../assets/arrow_right_inactive.svg";
import "./PagenationBar.css";
import "./PaginationBar.css";

const calcPageArray = (totalPage, currentPage) => {
if (totalPage <= 5)
Expand All @@ -20,55 +20,52 @@ const calcPageArray = (totalPage, currentPage) => {
.map((start, idx) => start + idx);
};

export default function PagenationBar({ totalPage, useParamObj }) {
const [paramObj, setParamObj] = useParamObj;

export default function PaginationBar({ totalPage, currentPage, onChange }) {
const pageArray = useMemo(
() => calcPageArray(totalPage, paramObj.page),
[totalPage, paramObj]
() => calcPageArray(totalPage, currentPage),
[totalPage, currentPage]
);

const checkPage = (page) => {
if (page === paramObj.page) return "pagenationBar__button--current";
if (page === currentPage) return "paginationBar__button--current";
};

const handlePrevClick = useCallback(() => {
setParamObj((prevObj) => ({ ...prevObj, page: paramObj.page - 1 }));
}, [paramObj, setParamObj]);
onChange(Math.max(currentPage - 5, 1));
}, [onChange, currentPage]);

const handleNextClick = useCallback(() => {
setParamObj((prevObj) => ({ ...prevObj, page: paramObj.page + 1 }));
}, [paramObj, setParamObj]);
onChange(Math.min(currentPage + 5, totalPage));
}, [onChange, currentPage, totalPage]);

const handleNumberClick = useCallback(
(e) => {
setParamObj((prevObj) => ({
...prevObj,
page: Number(e.target.textContent),
}));
onChange(Number(e.target.textContent));
},
[setParamObj]
[onChange]
);

return (
<nav className="pagenationBar">
<ul className="pagenationBar__wrapper">
<nav className="paginationBar">
<ul className="paginationBar__wrapper">
<li>
<button
className="pagenationBar__button"
className="paginationBar__button"
type="button"
onClick={handlePrevClick}
disabled={paramObj.page === 1}
disabled={currentPage === 1}
>
<img
src={paramObj.page !== 1 ? prevPageIcon : inPrevPageIcon}
src={currentPage !== 1 ? prevPageIcon : inPrevPageIcon}
alt="이전 페이지"
/>
</button>
</li>
{pageArray.map((page) => (
<li key={page}>
<button
className={`pagenationBar__button ${checkPage(page)}`}
className={`paginationBar__button ${checkPage(page)}`}
type="button"
onClick={handleNumberClick}
aria-label={`${page}번 페이지`}
>
Expand All @@ -78,12 +75,13 @@ export default function PagenationBar({ totalPage, useParamObj }) {
))}
<li>
<button
className="pagenationBar__button"
className="paginationBar__button"
type="button"
onClick={handleNextClick}
disabled={paramObj.page === totalPage}
disabled={currentPage === totalPage}
>
<img
src={paramObj.page !== totalPage ? nextPageIcon : inNextPageIcon}
src={currentPage !== totalPage ? nextPageIcon : inNextPageIcon}
alt="다음 페이지"
/>
</button>
Expand Down
File renamed without changes.
51 changes: 51 additions & 0 deletions src/components/layout/Header.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
import { Link, NavLink } from "react-router-dom";
import { useMediaQuery } from "../../hooks/useMediaQuery.js";
import logo from "../../assets/logo_w153x3.png";
import logoText from "../../assets/logo_w81x3.png";
import profileImage from "../../assets/profile_image_w40x3.png";
import "./Header.css";

export default function Header() {
const media = useMediaQuery();

const getLogo = (media) => {
return media !== "MOBLE" ? logo : logoText;
};

return (
<header className="header">
<Link to="/">
<img
className="header__logo"
src={getLogo(media)}
alt="판다마켓 바로가기"
/>
</Link>
<nav className="header__nav">
<ul className="header__navList">
<li>
<NavLink
className={({ isActive }) =>
isActive ? "header__navItem--active" : undefined
}
to="/boards"
>
자유게시판
</NavLink>
</li>
<li>
<NavLink
className={({ isActive }) =>
isActive ? "header__navItem--active" : undefined
}
to="/items"
>
중고마켓
</NavLink>
</li>
</ul>
</nav>
<img className="header__profile" src={profileImage} alt="프로필 사진" />
</header>
);
}
41 changes: 3 additions & 38 deletions src/components/layout/Layout.js
Original file line number Diff line number Diff line change
@@ -1,45 +1,10 @@
import { Link, Outlet, useLocation } from "react-router-dom";

import { useMediaQuery } from "../../hooks/useMediaQuery.js";
import logo from "../../assets/logo_w153x3.png";
import logoText from "../../assets/logo_w81x3.png";
import profileImage from "../../assets/profile_image_w40x3.png";
import "./Layout.css";
import { Outlet } from "react-router-dom";
import Header from "./Header.js";

export default function Layout() {
const { pathname } = useLocation();
const media = useMediaQuery();

const getLogo = (media) => {
return media !== "MOBLE" ? logo : logoText;
};

const checkPath = (path) => {
return pathname === path ? "header__navItem--active" : undefined;
};

return (
<>
<header className="header">
<Link to="/">
<img
className="header__logo"
src={getLogo(media)}
alt="판다마켓 바로가기"
/>
</Link>
<nav className="header__nav">
<ul className="header__navList">
<li className={checkPath("/boards")}>
<Link to="/boards">자유게시판</Link>
</li>
<li className={checkPath("/items")}>
<Link to="/items">중고마켓</Link>
</li>
</ul>
</nav>
<img className="header__profile" src={profileImage} alt="프로필 사진" />
</header>
<Header />
<Outlet />
Copy link
Collaborator

Choose a reason for hiding this comment

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

P3:
👍

</>
);
Expand Down
Loading
Loading