Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
f4953f1
refactor: getProducts 함수 async, await 제거
SanginJeong Aug 29, 2025
43b8527
refactor: 한 페이지에 h1 중복이슈로 h2 로 변경
SanginJeong Aug 29, 2025
e49c41c
refactor: DROPDOWN_MENUS 컴포넌트 밖으로 빼기
SanginJeong Aug 29, 2025
0450059
feat: ItemDetailPage 생성 및 라우팅 설정
SanginJeong Aug 29, 2025
b91d9b9
저장용 커밋
SanginJeong Aug 29, 2025
ff63e22
feat: 상품 상세 페이지 이동
SanginJeong Aug 30, 2025
df24567
feat: 상품 상세 정보 받아오는 Hook 구현
SanginJeong Aug 30, 2025
50b004a
feat: 상품 코멘트 받아오는 Hook 구현
SanginJeong Aug 30, 2025
76c1f90
refactor: item -> product 로이름 변경 및 통일
SanginJeong Aug 31, 2025
7d76bd0
refactor: addItem -> addProduct 로 클래스명 통일 및 변경
SanginJeong Aug 31, 2025
8708240
feat: 상품 디테일 정보 디자인
SanginJeong Sep 3, 2025
e2c5a09
feat: 상품 문의하기 디자인 구현
SanginJeong Sep 3, 2025
cafb4fa
refactor: 상품 문의하기 div -> form 으로 변경
SanginJeong Sep 3, 2025
2efefe6
feat: 댓글 목록 디자인 및 UserInfo 공통 컴포넌트로 구현
SanginJeong Sep 3, 2025
1a55ab5
refactor: dropdown 구조 수정
SanginJeong Sep 3, 2025
2727a11
feat: 목록으로 돌아가기 기능 구현
SanginJeong Sep 3, 2025
2163fe8
feat: useNavigate 페이지 이동시 스크롤 최상단 이동 구현
SanginJeong Sep 3, 2025
b623604
feat: 수정하기 부분 구현 및 구조 리팩토링
SanginJeong Sep 3, 2025
edd0640
feat: 문의가 없을 때 없음 이미지 보여주기 구현
SanginJeong Sep 4, 2025
0cdd8b2
refactor: Comment 컴포넌트를 만들어서 구조변경 -> 핸들러 함수들 리팩토링
SanginJeong Sep 4, 2025
82c6a30
refactor: trim() 이용해서 빈 문자열 입력 시에도 disabled 되도록 수정
SanginJeong Sep 4, 2025
645dfd3
refactor: placeholder 길이가 길어서 상수로 빼기
SanginJeong Sep 4, 2025
2eebc08
refactor: input name 속성을 활용해 handleChange 간단하게 만들기
SanginJeong Sep 4, 2025
ce74b65
feat: 반응형 사이즈 구현
SanginJeong Sep 4, 2025
c5a838b
fix: 오타수정
SanginJeong Sep 4, 2025
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
6 changes: 3 additions & 3 deletions vite-project/package-lock.json

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

17 changes: 17 additions & 0 deletions vite-project/public/images/Img_inquiry_empty.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
4 changes: 4 additions & 0 deletions vite-project/public/images/ic_back.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
5 changes: 5 additions & 0 deletions vite-project/public/images/ic_kebab.svg
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
18 changes: 17 additions & 1 deletion vite-project/src/App.css
Original file line number Diff line number Diff line change
Expand Up @@ -3,9 +3,17 @@
--primary200: #1967d6;
--primary300: #1251aa;

--secondary200: #e5e7eb;
--secondary300: #e5e7eb;
--secondary400: #9ca3af;
--secondary500: #6b7280;
--secondary600: #4b5563;
--secondary800: #1f2937;

--gray50: #f9fafb;
--gray100: #f3f4f6;
--gray200: #e5e7eb;
--gray300: #d1d5db;
--gray400: #9ca3af;
--gray500: #6b7280;
--gray600: #4b5563;
Expand Down Expand Up @@ -70,8 +78,10 @@ p {
}

.btn-medium {
width: 240px;
height: 48px;
padding: 12px 71px;
padding: 12px 64px;
white-space: nowrap;
border-radius: 40px;
border: none;
font-weight: 600;
Expand Down Expand Up @@ -117,6 +127,12 @@ p {
align-items: center;
}

.kebab-btn {
display: flex;
justify-content: center;
align-items: center;
}

.container {
max-width: 1200px;
margin: 0 auto;
Expand Down
14 changes: 9 additions & 5 deletions vite-project/src/App.jsx
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
import "./App.css";
import { Route, Routes, Navigate } from "react-router";
import ItemsPage from "./pages/ItemsPage";
import AddItemPage from "./pages/AddItemPage";
import ProductsPage from "./pages/ProductsPage";
import AddProductPage from "./pages/AddProductPage";
import Layout from "./layout/Layout";
import FreeBoard from "./pages/FreeBoardPage";
import ProductDetailPage from "./pages/ProductDetailPage";

function App() {
return (
Expand All @@ -12,10 +13,13 @@ function App() {
<Route path="/" element={<Navigate to="/items" />} />

<Route element={<Layout />}>
<Route path="/items" element={<ItemsPage />} />
<Route path="/addItem" element={<AddItemPage />} />
<Route path="/items">
<Route index element={<ProductsPage />} />
<Route path=":productId" element={<ProductDetailPage />} />
</Route>
<Route path="/addItem" element={<AddProductPage />} />
{/* freeBoard : link active 테스트를 위해 미리 만듦 */}
<Route path="/freeBoard" element={<FreeBoard />} />{" "}
<Route path="/freeBoard" element={<FreeBoard />} />
</Route>
</Routes>
);
Expand Down
18 changes: 7 additions & 11 deletions vite-project/src/common/Dropdown/index.jsx
Original file line number Diff line number Diff line change
@@ -1,19 +1,15 @@
import React, { useState } from "react";
const DropDown = ({ children, className }) => {
return <div className={`dropdown ${className}`}>{children}</div>;
};

const DropDown = ({ children }) => {
return <div className="dropdown">{children}</div>;
DropDown.header = ({ children }) => {
return <div>{children}</div>;
Comment on lines +5 to +6
Copy link
Collaborator

Choose a reason for hiding this comment

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

크으.. 상인님 코드를 볼 때마다 느끼는거지만 유지보수에 신경을 많이 쓰시는 것 같아요.

그냥 Dorpdown children<div>로처리하셨을 수도 있었을텐데, 드롭다운이 공통적으로 변경되는 것도 고려하여 이렇게 설계하신게 느껴집니다.. 👍

};

DropDown.header = ({ children, onClick }) => {
DropDown.menus = ({ children, isOpen, className }) => {
return (
<button onClick={onClick} className="button dropdown-btn">
{children}
</button>
isOpen && <ul className={`dropdown-menus ${className}`}>{children}</ul>
);
};

DropDown.menus = ({ children, isOpen }) => {
return isOpen && <ul className="dropdown-menus">{children}</ul>;
};

export default DropDown;
1 change: 0 additions & 1 deletion vite-project/src/common/ProductCard/index.jsx
Original file line number Diff line number Diff line change
@@ -1,4 +1,3 @@
import React from "react";
import "./ProductCard.style.css";

const ProductCard = ({ product, category }) => {
Expand Down
3 changes: 1 addition & 2 deletions vite-project/src/common/ProductList/index.jsx
Original file line number Diff line number Diff line change
@@ -1,12 +1,11 @@
import React from "react";
import { Link } from "react-router";
import ProductCard from "../ProductCard";
const ProductList = ({ products, className }) => {
return (
<ul className={className}>
{products?.map((product) => (
<li key={product.id}>
<Link>
<Link to={`${product.id}`}>
<ProductCard product={product} category="all-card-img" />
</Link>
</li>
Expand Down
14 changes: 14 additions & 0 deletions vite-project/src/common/ScrollToTop/index.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
import { useEffect } from "react";
import { useLocation } from "react-router";

const ScrollToTop = () => {
const { pathname } = useLocation();

useEffect(() => {
window.scrollTo(0, 0);
}, [pathname]);

return null;
};
Comment on lines +4 to +12
Copy link
Collaborator

Choose a reason for hiding this comment

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

오잉? 요건 그냥 훅으로 만들어도 되겠는데요?

Suggested change
const ScrollToTop = () => {
const { pathname } = useLocation();
useEffect(() => {
window.scrollTo(0, 0);
}, [pathname]);
return null;
};
const useFixTop = () => {
const { pathname } = useLocation();
useEffect(() => {
window.scrollTo(0, 0);
}, [pathname]);
};

컴포넌트는 보통 실체하는 ui가 있을 때 사용되는건데 이건 컴포넌트로 보긴 어렵겠네요.


export default ScrollToTop;
1 change: 1 addition & 0 deletions vite-project/src/common/TagBadge/TagBadge.style.css
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
display: inline-flex;
justify-content: center;
align-items: center;
white-space: nowrap;
gap: 10px;
}

Expand Down
8 changes: 5 additions & 3 deletions vite-project/src/common/TagBadge/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -4,9 +4,11 @@ const TagBadge = ({ name, onDelete }) => {
return (
<div className="tag-badge">
<span>#{name}</span>
<button className="button ic-x-btn" onClick={onDelete}>
<img src="images/ic_x.svg" alt="태그 삭제 이미지" />
</button>
{onDelete && (
<button className="button ic-x-btn" onClick={onDelete}>
<img src="/images/ic_x.svg" alt="태그 삭제 이미지" />
</button>
)}
</div>
);
};
Expand Down
1 change: 1 addition & 0 deletions vite-project/src/common/TagList/TagList.style.css
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
.tag-area {
display: flex;
gap: 16px;
flex-wrap: wrap;
}
5 changes: 4 additions & 1 deletion vite-project/src/common/TagList/index.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,10 @@ const TagList = ({ tags, onDelete }) => {
<ul className="tag-area">
{tags?.map((tag, index) => (
<li key={tag}>
<TagBadge name={tag} onDelete={() => onDelete(index)} />
<TagBadge
name={tag}
onDelete={onDelete ? () => onDelete(index) : undefined}
Copy link
Collaborator

Choose a reason for hiding this comment

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

해당 코드는 다음과 같이 함축할 수 있겠네요 !

Suggested change
onDelete={onDelete ? () => onDelete(index) : undefined}
onDelete={onDelete && () => onDelete(index)}

어떻게 이게 가능할까요?

  • 자바스크립트에서 && 연산자는 앞의 값이 truthy일 때만 뒤의 값을 평가합니다.
  • 즉, onDelete가 존재하지 않으면 false가 반환되어 onDelete props에는 false가 들어갑니다.
  • React는 false, null, undefined를 렌더링하지 않는 값으로 처리하므로, 결과적으로 onDelete가 전달되지 않은 것과 동일하게 동작합니다.

/>
</li>
))}
</ul>
Expand Down
22 changes: 22 additions & 0 deletions vite-project/src/common/UserInfo/Userinfo.style.css
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
.userInfo-badge {
display: flex;
align-items: center;
gap: 16px;
}

.userInfo-badge-name-date {
display: flex;
flex-direction: column;
gap: 2px;
font-size: 14px;
}

.userInfo-badge-name {
color: var(--secondary600);
font-weight: 500;
}

.userInfo-badge-createdAt {
color: var(--gray400);
font-weight: 400;
}
16 changes: 16 additions & 0 deletions vite-project/src/common/UserInfo/index.jsx
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
import "./Userinfo.style.css";

const UserInfo = ({ image, name, date }) => {
const imageSrc = image || "/images/nav-panda.svg";
return (
<div className="userInfo-badge">
<img src={imageSrc} alt="이미지" />
<div className="userInfo-badge-name-date">
<span className="userInfo-badge-name">{name}</span>
<span className="userInfo-badge-date">{date}</span>
</div>
</div>
);
};

export default UserInfo;
2 changes: 2 additions & 0 deletions vite-project/src/constants/PLACEHOLDER.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
export const QUESTION_PLACEHOLDER =
"개인정보를 공유 및 요청하거나, 명예 훼손, 무단 광고, 불법 정보 유포시 모니터링 후 삭제될 수 있으며, 이에 대한 민형사상 책임은 게시자에게 있습니다.";
Comment on lines +1 to +2
Copy link
Collaborator

Choose a reason for hiding this comment

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

해당 상수는 파일을 분리함으로써 어떤 이득을 취할 수 있을까요? 🤔

사용되는 컴포넌트와 멀리 떨어져 있기에 개발 경험이 떨어질 수 있으며 유지보수를 위하기에는 재사용될 가능성이 낮아보일 것으로 사료되는군요 ..!
다국어를 지원하는 경우 텍스트들을 중앙집중형으로 관리하기도 하나, 지금은 다른 케이스인 것으로 보이는군요 😉

3 changes: 3 additions & 0 deletions vite-project/src/constants/PRODUCTS.js
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,7 @@ export const ORDER_BYS = {
최신순: "recent",
좋아요순: "favorite",
};

export const DROPDOWN_MENUS = Object.keys(ORDER_BYS);

export const GROUP_SIZE = 5;
20 changes: 20 additions & 0 deletions vite-project/src/hooks/useDeleteProductCommentQuery.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
import { useMutation, useQueryClient } from "@tanstack/react-query";
import instance from "../api/axiosInstance";

const deleteProductComment = ({ commentId }) => {
return instance.delete(`comments/${commentId}`);
};

export const useDeleteProductCommentQuery = () => {
const queryClient = useQueryClient();

return useMutation({
mutationFn: deleteProductComment,
onSuccess: () => {
queryClient.invalidateQueries(["getProductComments"]);
},
onError: (error) => {
console.log(error);
},
});
};
17 changes: 17 additions & 0 deletions vite-project/src/hooks/useGetProductComments.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { useQuery } from "@tanstack/react-query";
import instance from "../api/axiosInstance";

const getProductComments = ({ productId, limit, cursor }) => {
return instance.get(`products/${productId}/comments`, {
params: { limit, cursor },
});
};

export const useGetProductCommentsQuery = ({ productId, limit, cursor }) => {
return useQuery({
queryKey: ["getProductComments", productId, limit],
Copy link
Collaborator

Choose a reason for hiding this comment

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

그런데, cursor도 함께 쿼리키에 포함하여야 하지 않을까요?

Suggested change
queryKey: ["getProductComments", productId, limit],
queryKey: ["getProductComments", productId, limit, cursor],

두 번째 커서, 세 번째 커서, 각기 다른 결과값을 가져올 것으로 보여서요 !

queryFn: () => getProductComments({ productId, limit, cursor }),
staleTime: 300000,
select: (response) => response.data,
});
Comment on lines +10 to +16
Copy link
Collaborator

Choose a reason for hiding this comment

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

크으.. 기초 프로젝트 때 익히신 react-query를 사용해보셨군요 ! 😊

배우신 것을 바로 응용해보시는 상인님의 학습 열정 리스펙합니다 👍👍

};
15 changes: 15 additions & 0 deletions vite-project/src/hooks/useGetProductDetail.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
import { useQuery } from "@tanstack/react-query";
import instance from "../api/axiosInstance";

const getProductDetail = ({ productId }) => {
return instance.get(`products/${productId}`);
};

export const useGetProductDetailQuery = ({ productId }) => {
return useQuery({
queryKey: ["getProductDetail", productId],
queryFn: () => getProductDetail({ productId }),
staleTime: 300000,
select: (response) => response.data,
});
};
4 changes: 2 additions & 2 deletions vite-project/src/hooks/useGetProducts.js
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
import { useQuery } from "@tanstack/react-query";
import instance from "../api/axiosInstance";

const getProducts = async ({ page = 1, orderBy = "recent", pageSize = 10 }) => {
return await instance.get("/products", {
const getProducts = ({ page = 1, orderBy = "recent", pageSize = 10 }) => {
return instance.get("/products", {
params: { page, orderBy, pageSize },
});
};
Expand Down
2 changes: 2 additions & 0 deletions vite-project/src/main.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,14 @@ import { createRoot } from "react-dom/client";
import { BrowserRouter } from "react-router";
import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
import App from "./App.jsx";
import ScrollToTop from "./common/ScrollToTop/index.jsx";

const queryClient = new QueryClient();

createRoot(document.getElementById("root")).render(
<QueryClientProvider client={queryClient}>
<BrowserRouter>
<ScrollToTop />
<App />
</BrowserRouter>
</QueryClientProvider>
Expand Down

This file was deleted.

This file was deleted.

Loading
Loading