diff --git a/vite-project/package-lock.json b/vite-project/package-lock.json
index 58b22412..2d7d880b 100644
--- a/vite-project/package-lock.json
+++ b/vite-project/package-lock.json
@@ -2884,9 +2884,9 @@
}
},
"node_modules/react-router": {
- "version": "7.7.0",
- "resolved": "https://registry.npmjs.org/react-router/-/react-router-7.7.0.tgz",
- "integrity": "sha512-3FUYSwlvB/5wRJVTL/aavqHmfUKe0+Xm9MllkYgGo9eDwNdkvwlJGjpPxono1kCycLt6AnDTgjmXvK3/B4QGuw==",
+ "version": "7.8.2",
+ "resolved": "https://registry.npmjs.org/react-router/-/react-router-7.8.2.tgz",
+ "integrity": "sha512-7M2fR1JbIZ/jFWqelpvSZx+7vd7UlBTfdZqf6OSdF9g6+sfdqJDAWcak6ervbHph200ePlu+7G8LdoiC3ReyAQ==",
"license": "MIT",
"dependencies": {
"cookie": "^1.0.1",
diff --git a/vite-project/public/images/ic_back.svg b/vite-project/public/images/ic_back.svg
new file mode 100644
index 00000000..9ba5ad94
--- /dev/null
+++ b/vite-project/public/images/ic_back.svg
@@ -0,0 +1,4 @@
+
diff --git a/vite-project/public/images/ic_kebab.svg b/vite-project/public/images/ic_kebab.svg
new file mode 100644
index 00000000..dd7ed7f5
--- /dev/null
+++ b/vite-project/public/images/ic_kebab.svg
@@ -0,0 +1,5 @@
+
diff --git a/vite-project/src/App.css b/vite-project/src/App.css
index cd559b3c..596fa193 100644
--- a/vite-project/src/App.css
+++ b/vite-project/src/App.css
@@ -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;
@@ -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;
@@ -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;
diff --git a/vite-project/src/App.jsx b/vite-project/src/App.jsx
index 8ad11bfe..7fe10905 100644
--- a/vite-project/src/App.jsx
+++ b/vite-project/src/App.jsx
@@ -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 (
@@ -12,10 +13,13 @@ function App() {
} />
}>
- } />
- } />
+
+ } />
+ } />
+
+ } />
{/* freeBoard : link active 테스트를 위해 미리 만듦 */}
- } />{" "}
+ } />
);
diff --git a/vite-project/src/common/Dropdown/index.jsx b/vite-project/src/common/Dropdown/index.jsx
index e94bafbb..f3752fdf 100644
--- a/vite-project/src/common/Dropdown/index.jsx
+++ b/vite-project/src/common/Dropdown/index.jsx
@@ -1,15 +1,9 @@
-import React, { useState } from "react";
-
const DropDown = ({ children }) => {
return
{children}
;
};
-DropDown.header = ({ children, onClick }) => {
- return (
-
- );
+DropDown.header = ({ children }) => {
+ return {children}
;
};
DropDown.menus = ({ children, isOpen }) => {
diff --git a/vite-project/src/common/ProductCard/index.jsx b/vite-project/src/common/ProductCard/index.jsx
index 35795ae4..e803d0a6 100644
--- a/vite-project/src/common/ProductCard/index.jsx
+++ b/vite-project/src/common/ProductCard/index.jsx
@@ -1,4 +1,3 @@
-import React from "react";
import "./ProductCard.style.css";
const ProductCard = ({ product, category }) => {
diff --git a/vite-project/src/common/ProductList/index.jsx b/vite-project/src/common/ProductList/index.jsx
index 10308393..21278c2f 100644
--- a/vite-project/src/common/ProductList/index.jsx
+++ b/vite-project/src/common/ProductList/index.jsx
@@ -1,4 +1,3 @@
-import React from "react";
import { Link } from "react-router";
import ProductCard from "../ProductCard";
const ProductList = ({ products, className }) => {
@@ -6,7 +5,7 @@ const ProductList = ({ products, className }) => {
{products?.map((product) => (
-
-
+
diff --git a/vite-project/src/common/ScrollToTop/index.jsx b/vite-project/src/common/ScrollToTop/index.jsx
new file mode 100644
index 00000000..ab426d23
--- /dev/null
+++ b/vite-project/src/common/ScrollToTop/index.jsx
@@ -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;
+};
+
+export default ScrollToTop;
diff --git a/vite-project/src/common/TagBadge/TagBadge.style.css b/vite-project/src/common/TagBadge/TagBadge.style.css
index f5a936b8..979e5f19 100644
--- a/vite-project/src/common/TagBadge/TagBadge.style.css
+++ b/vite-project/src/common/TagBadge/TagBadge.style.css
@@ -6,6 +6,7 @@
display: inline-flex;
justify-content: center;
align-items: center;
+ white-space: nowrap;
gap: 10px;
}
diff --git a/vite-project/src/common/TagBadge/index.jsx b/vite-project/src/common/TagBadge/index.jsx
index ddda26e9..e7f80fcd 100644
--- a/vite-project/src/common/TagBadge/index.jsx
+++ b/vite-project/src/common/TagBadge/index.jsx
@@ -4,9 +4,11 @@ const TagBadge = ({ name, onDelete }) => {
return (
#{name}
-
+ {onDelete && (
+
+ )}
);
};
diff --git a/vite-project/src/common/TagList/index.jsx b/vite-project/src/common/TagList/index.jsx
index f5443253..93d6926a 100644
--- a/vite-project/src/common/TagList/index.jsx
+++ b/vite-project/src/common/TagList/index.jsx
@@ -6,7 +6,10 @@ const TagList = ({ tags, onDelete }) => {
{tags?.map((tag, index) => (
-
- onDelete(index)} />
+ onDelete(index) : undefined}
+ />
))}
diff --git a/vite-project/src/common/UserInfo/Userinfo.style.css b/vite-project/src/common/UserInfo/Userinfo.style.css
new file mode 100644
index 00000000..3622a31c
--- /dev/null
+++ b/vite-project/src/common/UserInfo/Userinfo.style.css
@@ -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;
+}
diff --git a/vite-project/src/common/UserInfo/index.jsx b/vite-project/src/common/UserInfo/index.jsx
new file mode 100644
index 00000000..0247033e
--- /dev/null
+++ b/vite-project/src/common/UserInfo/index.jsx
@@ -0,0 +1,16 @@
+import "./UserInfo.style.css";
+
+const UserInfo = ({ image, name, date }) => {
+ const imageSrc = image || "/images/nav-panda.svg";
+ return (
+
+

+
+ {name}
+ {date}
+
+
+ );
+};
+
+export default UserInfo;
diff --git a/vite-project/src/constants/PRODUCTS.js b/vite-project/src/constants/PRODUCTS.js
index c08eb7c1..199f9aa5 100644
--- a/vite-project/src/constants/PRODUCTS.js
+++ b/vite-project/src/constants/PRODUCTS.js
@@ -2,4 +2,7 @@ export const ORDER_BYS = {
최신순: "recent",
좋아요순: "favorite",
};
+
+export const DROPDOWN_MENUS = Object.keys(ORDER_BYS);
+
export const GROUP_SIZE = 5;
diff --git a/vite-project/src/hooks/useDeleteProductCommentQuery.js b/vite-project/src/hooks/useDeleteProductCommentQuery.js
new file mode 100644
index 00000000..fa940854
--- /dev/null
+++ b/vite-project/src/hooks/useDeleteProductCommentQuery.js
@@ -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);
+ },
+ });
+};
diff --git a/vite-project/src/hooks/useGetProductComments.js b/vite-project/src/hooks/useGetProductComments.js
new file mode 100644
index 00000000..3acf069f
--- /dev/null
+++ b/vite-project/src/hooks/useGetProductComments.js
@@ -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],
+ queryFn: () => getProductComments({ productId, limit, cursor }),
+ staleTime: 300000,
+ select: (response) => response.data,
+ });
+};
diff --git a/vite-project/src/hooks/useGetProductDetail.js b/vite-project/src/hooks/useGetProductDetail.js
new file mode 100644
index 00000000..59a5ebba
--- /dev/null
+++ b/vite-project/src/hooks/useGetProductDetail.js
@@ -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,
+ });
+};
diff --git a/vite-project/src/hooks/useGetProducts.js b/vite-project/src/hooks/useGetProducts.js
index 13c36521..6c675255 100644
--- a/vite-project/src/hooks/useGetProducts.js
+++ b/vite-project/src/hooks/useGetProducts.js
@@ -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 },
});
};
diff --git a/vite-project/src/main.jsx b/vite-project/src/main.jsx
index 4025443e..41be83a7 100644
--- a/vite-project/src/main.jsx
+++ b/vite-project/src/main.jsx
@@ -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(
+
diff --git a/vite-project/src/pages/AddItemPage/components/AddItemFormHeader/index.jsx b/vite-project/src/pages/AddItemPage/components/AddItemFormHeader/index.jsx
deleted file mode 100644
index 53e28e2a..00000000
--- a/vite-project/src/pages/AddItemPage/components/AddItemFormHeader/index.jsx
+++ /dev/null
@@ -1,22 +0,0 @@
-const AddItemFormHeader = ({ formData }) => {
- const isDisabled =
- formData.name &&
- formData.price &&
- formData.description &&
- formData.tags.length > 0;
-
- return (
-
-
상품 등록하기
-
-
- );
-};
-
-export default AddItemFormHeader;
diff --git a/vite-project/src/pages/AddItemPage/components/AddItemTagList/index.jsx b/vite-project/src/pages/AddItemPage/components/AddItemTagList/index.jsx
deleted file mode 100644
index e9f81799..00000000
--- a/vite-project/src/pages/AddItemPage/components/AddItemTagList/index.jsx
+++ /dev/null
@@ -1,9 +0,0 @@
-import TagBadge from "../../../../common/TagBadge";
-
-const AddItemTagList = ({ tags }) => {
- return (
-
- );
-};
-
-export default AddItemTagList;
diff --git a/vite-project/src/pages/AddItemPage/AddItemPage.style.css b/vite-project/src/pages/AddProductPage/AddProductPage.style.css
similarity index 64%
rename from vite-project/src/pages/AddItemPage/AddItemPage.style.css
rename to vite-project/src/pages/AddProductPage/AddProductPage.style.css
index dc13d896..7396b3f9 100644
--- a/vite-project/src/pages/AddItemPage/AddItemPage.style.css
+++ b/vite-project/src/pages/AddProductPage/AddProductPage.style.css
@@ -1,4 +1,4 @@
-.addItem-page-layout {
+.addProduct-page-layout {
margin-top: 90px;
display: flex;
flex-direction: column;
@@ -6,35 +6,35 @@
padding-bottom: 50px;
}
-.addItem-form {
+.addProduct-form {
display: flex;
flex-direction: column;
gap: 16px;
}
-.addItem-form-header {
+.addProduct-form-header {
display: flex;
justify-content: space-between;
align-items: center;
}
-.addItem-form-header-title {
+.addProduct-form-header-title {
font-weight: 700;
font-size: 20px;
color: var(--gray800);
}
-.addItem-form-submit-btn {
+.addProduct-form-submit-btn {
background-color: var(--primary100);
}
-.addItem-form-submit-btn:disabled {
+.addProduct-form-submit-btn:disabled {
background-color: var(--gray400);
}
-.addItem-input,
-.addItem-textArea,
-.addItem-image-input {
+.addProduct-input,
+.addProduct-textArea,
+.addProduct-image-input {
background-color: var(--gray100);
padding: 16px 24px;
border-radius: 12px;
@@ -44,12 +44,12 @@
color: #1f2937;
}
-.addItem-input,
-.addItem-textArea {
+.addProduct-input,
+.addProduct-textArea {
width: 100%;
}
-.addItem-image-input {
+.addProduct-image-input {
cursor: pointer;
display: flex;
flex-direction: column;
@@ -59,38 +59,38 @@
color: var(--gray400);
}
-.addItem-image-input,
-.addItem-image-card {
+.addProduct-image-input,
+.addProduct-image-card {
aspect-ratio: 1;
width: 282px;
}
-.addItem-textArea {
+.addProduct-textArea {
height: 282px;
resize: none;
}
-.addItem-image-area {
+.addProduct-image-area {
display: flex;
gap: 16px;
}
-.addItem-image-card {
+.addProduct-image-card {
position: relative;
}
-.addItem-image-card > button {
+.addProduct-image-card > button {
position: absolute;
right: 10px;
top: 10px;
}
@media screen and (max-width: 767px) {
- .addItem-image-input,
- .addItem-image-card {
+ .addProduct-image-input,
+ .addProduct-image-card {
width: 160px;
}
- .addItem-image-area {
+ .addProduct-image-area {
gap: 10px;
}
}
diff --git a/vite-project/src/pages/AddItemPage/components/AddItemDescription/index.jsx b/vite-project/src/pages/AddProductPage/components/AddProductDescription/index.jsx
similarity index 61%
rename from vite-project/src/pages/AddItemPage/components/AddItemDescription/index.jsx
rename to vite-project/src/pages/AddProductPage/components/AddProductDescription/index.jsx
index d7a0ec23..f195400e 100644
--- a/vite-project/src/pages/AddItemPage/components/AddItemDescription/index.jsx
+++ b/vite-project/src/pages/AddProductPage/components/AddProductDescription/index.jsx
@@ -1,10 +1,10 @@
-const AddItemDescription = ({ value, onChange }) => {
+const AddProductDescription = ({ value, onChange }) => {
return (