-
Notifications
You must be signed in to change notification settings - Fork 39
[배수민] sprint5 #177
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
The head ref may contain hidden characters: "React-\uBC30\uC218\uBBFC-sprint5"
[배수민] sprint5 #177
Changes from 42 commits
b2e37bd
6f8bbb0
e11e25f
212e864
4dc5dd0
efca996
eaf83f9
c07e11a
1616a04
dffa4ab
26d0953
1b78b7a
8061b81
7f62fff
61f616e
a3078eb
1a489d0
440da35
8f60c74
40c3112
1f08632
fb689b6
2c97ce3
69e8454
a7d3e44
06c5c80
63ad325
ad48df5
ec79f34
fb1ead5
2dd2492
9dd0261
f3e79fd
39c7747
594db4f
5de1c0b
d6eea78
8b8d521
4ae4164
84b64b4
92a7001
c111d87
7330acd
c702f43
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -21,3 +21,5 @@ | |
| npm-debug.log* | ||
| yarn-debug.log* | ||
| yarn-error.log* | ||
| .eslint.config.js | ||
| .prettierrc.js | ||
Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,24 @@ | ||
| import { BrowserRouter, Routes, Route } from "react-router-dom"; | ||
| import App from "./App"; | ||
| import "./css/base/reset.css"; | ||
| import "./css/base/variables.css"; | ||
| import "./css/base/common.css"; | ||
| import ItemsPage from "./pages/ItemsPage"; | ||
| import ItemRegisterPage from "./pages/ItemRegisterPage"; | ||
|
|
||
| function Main() { | ||
| return ( | ||
| <BrowserRouter> | ||
| <Routes> | ||
| <Route path="/" element={<App />}> | ||
| <Route path="items"> | ||
| <Route index element={<ItemsPage />}></Route> | ||
| <Route path="addItem" element={<ItemRegisterPage />}></Route> | ||
| </Route> | ||
| </Route> | ||
| </Routes> | ||
| </BrowserRouter> | ||
| ); | ||
| } | ||
|
|
||
| export default Main; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,30 @@ | ||
| const BASEURL = "https://panda-market-api.vercel.app"; | ||
|
|
||
| export async function getFavoriteItems({ | ||
| page = 1, | ||
| pageSize = 4, | ||
| orderBy = "favorite", | ||
| }) { | ||
| const query = `page=${page}&pageSize=${pageSize}&orderBy=${orderBy}`; | ||
| const response = await fetch(`${BASEURL}/products?${query}`); | ||
| if (!response.ok) { | ||
| throw new Error("상품 목록을 불러오는데 오류가 발생했습니다"); | ||
| } | ||
| const body = await response.json(); | ||
| return body; | ||
| } | ||
|
|
||
| export async function getAllItems({ | ||
| page = 1, | ||
| pageSize = 10, | ||
| orderBy = "recent", | ||
| keyword = "", | ||
| }) { | ||
| const query = `page=${page}&pageSize=${pageSize}&orderBy=${orderBy}&keyword=${keyword}`; | ||
| const response = await fetch(`${BASEURL}/products?${query}`); | ||
| if (!response.ok) { | ||
| throw new Error("상품 목록을 불러오는데 오류가 발생했습니다"); | ||
| } | ||
| const body = await response.json(); | ||
| return body; | ||
| } | ||
|
Collaborator
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 굳굳! 스타일링에 관련된 props를 늘리지않고 type을 받는 방식으로 구조화하셨네요. 이렇게되면 명확한 props만 남게되어 유지보수에도 좋고 파일을 쉽게 확장하는것도 가능해지겠죠? 왜 props의 종류가 많아지는게 좋지 않은지는 아래 아티클 참고해보세요!
Collaborator
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 확장성 고려해서 컴포넌트를 만들어야 겠다는 생각이 드네요 |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,17 @@ | ||
| import { Link } from "react-router-dom"; | ||
| import "../css/components/Button.css"; | ||
|
|
||
| function Button({ className, type, to }) { | ||
| const btnStyleClass = { | ||
| register: "btn-register", | ||
| small: "btn-small", | ||
| large: "btn-large", | ||
| }; | ||
| return ( | ||
| <button className={`btn ${btnStyleClass[type]} ${className}`}> | ||
| <Link to={to}>상품 등록하기</Link> | ||
| </button> | ||
| ); | ||
| } | ||
|
|
||
| export default Button; |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,31 @@ | ||
| import "../css/components/Card.css"; | ||
| import heartIcon from "../img/heart.svg"; | ||
| import defaultImg from "../img/img_default.svg"; | ||
| function Card({ data }) { | ||
|
||
| return ( | ||
| <div> | ||
| <img | ||
| className="card__image" | ||
| alt="중고상품 이미지" | ||
| src={data.images[0] ?? defaultImg} | ||
| onError={(e) => { | ||
| e.target.onError = null; | ||
| e.target.src = defaultImg; | ||
| }} | ||
| /> | ||
| <div className="card__info"> | ||
| <div className="card__info__title">{data.name}</div> | ||
| <div className="card__info__price"> | ||
| {data.price.toLocaleString("ko-KR")}원 | ||
| </div> | ||
|
|
||
| <div className="card__icon__group"> | ||
| <img src={heartIcon} alt="하트 아이콘" className="heart__icon" /> | ||
|
||
| <span className="heart__icon__count">{data.favoriteCount}</span> | ||
| </div> | ||
| </div> | ||
| </div> | ||
| ); | ||
| } | ||
|
|
||
| export default Card; | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,40 @@ | ||
| import "../css/components/Dropdown.css"; | ||
| import sortIcon from "../img/sort.svg"; | ||
| import arrowDownIcon from "../img/arrow_down.svg"; | ||
|
|
||
| function Dropdown({ | ||
| className, | ||
| onClickDropdown, | ||
| onClickDropdownItem, | ||
| dropdownList, | ||
| showDropdown, | ||
| value, | ||
| }) { | ||
| return ( | ||
| <div | ||
| className={`dropdown__container ${className}`} | ||
| onClick={onClickDropdown} | ||
| > | ||
| <div className="dropdown__button"> | ||
| <span className="dropdown__text">{value.name}</span> | ||
| <img | ||
| src={arrowDownIcon} | ||
| alt="드롭다운 아이콘" | ||
| className="dropdown__button__icon" | ||
| /> | ||
| <img src={sortIcon} alt="분류아이콘" className="dropdown__sort__icon" /> | ||
| </div> | ||
| {showDropdown && ( | ||
| <ul className="dropdown__list"> | ||
| {dropdownList?.map((item) => ( | ||
| <li key={item.value} onClick={() => onClickDropdownItem(item)}> | ||
| {item.name} | ||
| </li> | ||
| ))} | ||
|
||
| </ul> | ||
| )} | ||
| </div> | ||
| ); | ||
| } | ||
|
|
||
| export default Dropdown; | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,55 @@ | ||
| import { Link, NavLink } from "react-router-dom"; | ||
| import textLogoIcon from "../img/logo_text.jpg"; | ||
| import logoIcon from "../img/logo.svg"; | ||
| import userIcon from "../img/user.svg"; | ||
| import "../css/components/Nav.css"; | ||
|
|
||
| function getLinkStyle({ isActive }) { | ||
| return { | ||
| color: isActive ? `var(--color-primary-100)` : undefined, | ||
| }; | ||
| } | ||
|
|
||
| function Nav() { | ||
| return ( | ||
| <header className="header"> | ||
| <div className="header__content"> | ||
| <div className="header__content__navigation__group"> | ||
| <Link to="/"> | ||
| <img | ||
| src={textLogoIcon} | ||
| srcSet={`${textLogoIcon} 103w, ${logoIcon} 153w`} | ||
| sizes={"(min-width: 768px) 153px, 103px"} | ||
| alt="판다마켓 로고" | ||
| className="header__content__logo" | ||
| /> | ||
| </Link> | ||
| <ul> | ||
| <li> | ||
| <NavLink to="board" style={getLinkStyle}> | ||
| 자유게시판 | ||
| </NavLink> | ||
| </li> | ||
|
|
||
| <li> | ||
| <NavLink to="items" style={getLinkStyle}> | ||
| 중고마켓 | ||
| </NavLink> | ||
|
||
| </li> | ||
| </ul> | ||
| </div> | ||
| <div className="header__content__user"> | ||
| <Link to="user"> | ||
| <img | ||
| src={userIcon} | ||
| alt="사용자 아이콘" | ||
| className="header__content__user__icon" | ||
| /> | ||
| </Link> | ||
| </div> | ||
| </div> | ||
| </header> | ||
| ); | ||
| } | ||
|
|
||
| export default Nav; | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
URLSearchParams 객체 사용해서 여러개의 파라미터를 관리해보는 방법으로 바꾸면, 쿼리 스트링의 파싱, 조작, 인코딩 등의 작업을 간편하게 처리할 수 있으면서도 실수를 줄일 수 있겠죠? :)
아래 아티클 참고해보세요!
참고
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
URLSearchParams 사용하는 방식으로 변경하였습니다!