From 8d73d8c290f0d6fc4bc0ca09882cd9cc5de4ea37 Mon Sep 17 00:00:00 2001 From: nerte Date: Wed, 19 Feb 2025 04:59:08 +0900 Subject: [PATCH 01/38] =?UTF-8?q?[Refactor]=20ItemsList=20style=20?= =?UTF-8?q?=EB=B6=84=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/ItemsPage/ItemsList.jsx | 47 ++++++++++++++++++ .../{ItemsList.js => ItemsList.style.jsx} | 48 ------------------- 2 files changed, 47 insertions(+), 48 deletions(-) create mode 100644 src/pages/ItemsPage/ItemsList.jsx rename src/pages/ItemsPage/{ItemsList.js => ItemsList.style.jsx} (65%) diff --git a/src/pages/ItemsPage/ItemsList.jsx b/src/pages/ItemsPage/ItemsList.jsx new file mode 100644 index 00000000..5dc0aa83 --- /dev/null +++ b/src/pages/ItemsPage/ItemsList.jsx @@ -0,0 +1,47 @@ +import { useNavigate } from "react-router-dom"; +import useWindowSize from "../../hooks/useWindowSize"; +// +import * as S from "./ItemsList.style"; +import BtnHeart from "../../components/common/BtnHeart/BtnHeart"; + +// + +function ListItem({ value, items }) { + const navigate = useNavigate(); + const device = useWindowSize(); + return ( + navigate(`./${items.id}`)}> + + +
+ {items.name} + {items.price} 원 +
+ +
+
+
+ ); +} +export default function ItemsList({ value, items, device }) { + return ( +
+
+ + {items.map((item) => { + return ( +
  • + +
  • + ); + })} +
    +
    +
    + ); +} diff --git a/src/pages/ItemsPage/ItemsList.js b/src/pages/ItemsPage/ItemsList.style.jsx similarity index 65% rename from src/pages/ItemsPage/ItemsList.js rename to src/pages/ItemsPage/ItemsList.style.jsx index 65a37d41..5da1118b 100644 --- a/src/pages/ItemsPage/ItemsList.js +++ b/src/pages/ItemsPage/ItemsList.style.jsx @@ -1,8 +1,4 @@ -import { useNavigate } from "react-router-dom"; import styled from "styled-components"; -import useWindowSize from "../../hooks/useWindowSize"; -// -import BtnHeart from "../../components/common/BtnHeart/BtnHeart"; const ByDevice = { best: { @@ -99,47 +95,3 @@ const Item = styled.div` flex-direction: column; gap: 16px; `; - -// - -function ListItem({ value, items }) { - const navigate = useNavigate(); - const device = useWindowSize(); - return ( - navigate(`./${items.id}`)}> - - -
    - {items.name} - {items.price} 원 -
    - -
    -
    -
    - ); -} -function ItemsList({ value, items, device }) { - return ( -
    -
    - - {items.map((item) => { - return ( -
  • - -
  • - ); - })} -
    -
    -
    - ); -} - -export default ItemsList; From 409ee54213611203908f87555f048a0fe9a08ec9 Mon Sep 17 00:00:00 2001 From: nerte Date: Wed, 19 Feb 2025 05:02:38 +0900 Subject: [PATCH 02/38] =?UTF-8?q?[Chore]=20ItemsList=20=ED=8F=B4=EB=8D=94?= =?UTF-8?q?=20=EC=9D=B4=EB=8F=99,=20HomePage->ItemsPage=EB=A1=9C=20?= =?UTF-8?q?=EC=9D=B4=EB=A6=84=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Main.jsx | 4 ++-- src/{pages/ItemsPage => components/ItemsList}/ItemsList.jsx | 2 +- .../ItemsPage => components/ItemsList}/ItemsList.style.jsx | 0 .../HomePage.jsx => "src/pages/\bItemsPage/ItemsPage.jsx" | 2 +- .../pages/\bItemsPage/ItemsPage.style.jsx" | 0 5 files changed, 4 insertions(+), 4 deletions(-) rename src/{pages/ItemsPage => components/ItemsList}/ItemsList.jsx (94%) rename src/{pages/ItemsPage => components/ItemsList}/ItemsList.style.jsx (100%) rename src/pages/HomePage/HomePage.jsx => "src/pages/\bItemsPage/ItemsPage.jsx" (96%) rename src/pages/HomePage/HomePage.style.jsx => "src/pages/\bItemsPage/ItemsPage.style.jsx" (100%) diff --git a/src/Main.jsx b/src/Main.jsx index 7ac1c86c..9694938a 100644 --- a/src/Main.jsx +++ b/src/Main.jsx @@ -3,7 +3,7 @@ import { createGlobalStyle } from "styled-components"; // import LandingPage from "./pages/LandingPage/LandingPage.jsx"; import App from "./App.js"; -import HomePage from "./pages/HomePage/HomePage.jsx"; +import ItemsPage from "./pages/ItemsPage/ItemsPage.jsx"; import AddItem from "./pages/AddItem/AddItem.jsx"; import Product from "./pages/ProductPage/Product.jsx"; import Test from "./components/TestPage.jsx"; @@ -58,7 +58,7 @@ function Main() { } /> }> } /> - } /> + } /> } /> } /> diff --git a/src/pages/ItemsPage/ItemsList.jsx b/src/components/ItemsList/ItemsList.jsx similarity index 94% rename from src/pages/ItemsPage/ItemsList.jsx rename to src/components/ItemsList/ItemsList.jsx index 5dc0aa83..6f7499e6 100644 --- a/src/pages/ItemsPage/ItemsList.jsx +++ b/src/components/ItemsList/ItemsList.jsx @@ -2,7 +2,7 @@ import { useNavigate } from "react-router-dom"; import useWindowSize from "../../hooks/useWindowSize"; // import * as S from "./ItemsList.style"; -import BtnHeart from "../../components/common/BtnHeart/BtnHeart"; +import BtnHeart from "../common/BtnHeart/BtnHeart"; // diff --git a/src/pages/ItemsPage/ItemsList.style.jsx b/src/components/ItemsList/ItemsList.style.jsx similarity index 100% rename from src/pages/ItemsPage/ItemsList.style.jsx rename to src/components/ItemsList/ItemsList.style.jsx diff --git a/src/pages/HomePage/HomePage.jsx "b/src/pages/\bItemsPage/ItemsPage.jsx" similarity index 96% rename from src/pages/HomePage/HomePage.jsx rename to "src/pages/\bItemsPage/ItemsPage.jsx" index b5f759e1..ebd73464 100644 --- a/src/pages/HomePage/HomePage.jsx +++ "b/src/pages/\bItemsPage/ItemsPage.jsx" @@ -2,7 +2,7 @@ import { useEffect, useState } from "react"; import { Link } from "react-router-dom"; // import * as S from "./HomePage.style"; -import ItemsList from "../ItemsPage/ItemsList"; +import ItemsList from "../../components/ItemsList/ItemsList"; import { getProducts, bestProducts } from "../../api/product.api"; import PageCount from "../../components/pageCount"; import useWindowSize from "../../hooks/useWindowSize"; diff --git a/src/pages/HomePage/HomePage.style.jsx "b/src/pages/\bItemsPage/ItemsPage.style.jsx" similarity index 100% rename from src/pages/HomePage/HomePage.style.jsx rename to "src/pages/\bItemsPage/ItemsPage.style.jsx" From 78c3078a0523147d226057463c83fbfb53688902 Mon Sep 17 00:00:00 2001 From: nerte Date: Wed, 19 Feb 2025 05:10:34 +0900 Subject: [PATCH 03/38] =?UTF-8?q?[Chore]=20globalstyles=20=EB=B6=84?= =?UTF-8?q?=EB=A6=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Main.jsx | 45 +------------------- src/components/ItemsList/ItemsList.style.jsx | 12 +++--- "src/pages/\bItemsPage/ItemsPage.jsx" | 2 +- src/style/globalStyle.js | 42 ++++++++++++++++++ 4 files changed, 51 insertions(+), 50 deletions(-) create mode 100644 src/style/globalStyle.js diff --git a/src/Main.jsx b/src/Main.jsx index 9694938a..0d95dd60 100644 --- a/src/Main.jsx +++ b/src/Main.jsx @@ -1,54 +1,13 @@ import { Route, BrowserRouter, Routes } from "react-router-dom"; -import { createGlobalStyle } from "styled-components"; +import GlobalStyle from "./style/globalStyle.js"; // import LandingPage from "./pages/LandingPage/LandingPage.jsx"; import App from "./App.js"; -import ItemsPage from "./pages/ItemsPage/ItemsPage.jsx"; +import ItemsPage from "./pages/ItemsPage/ItemsPage.jsx"; import AddItem from "./pages/AddItem/AddItem.jsx"; import Product from "./pages/ProductPage/Product.jsx"; import Test from "./components/TestPage.jsx"; // -// -const GlobalStyle = createGlobalStyle` - * { - box-sizing: border-box; - } - body { - font-family: 'Pretendard', sans-serif; - font-display: swap; - margin: 0; - padding: 0; - } - html { - margin: 0; - padding: 0; - } - a { - text-decoration: none; - color: #ffffff; - } - p{ - margin: 0px; - } - @font-face { - font-family: 'Pretendard'; - src: url('https://fastly.jsdelivr.net/gh/Project-Noonnu/noonfonts_2107@1.1/Pretendard-Regular.woff2') format('woff2'); - src: url('https://fastly.jsdelivr.net/gh/Project-Noonnu/noonfonts_2107@1.1/Pretendard-Regular.woff') format('woff'); - font-display: swap; - font-weight: 400; - font-style: normal; -} - -@font-face { -font-family: "Pretendard"; -src: url('https://fastly.jsdelivr.net/gh/Project-Noonnu/noonfonts_2107@1.1/Pretendard-Bold.woff2') format('woff2'); -src: url('https://fastly.jsdelivr.net/gh/Project-Noonnu/noonfonts_2107@1.1/Pretendard-Bold.woff') format('woff'); - font-display: swap; - font-weight: 600; - font-style: normal; -} -`; -// function Main() { return ( <> diff --git a/src/components/ItemsList/ItemsList.style.jsx b/src/components/ItemsList/ItemsList.style.jsx index 5da1118b..fffd3dcd 100644 --- a/src/components/ItemsList/ItemsList.style.jsx +++ b/src/components/ItemsList/ItemsList.style.jsx @@ -46,7 +46,7 @@ const ByDevice = { }, }, }; -const Title = styled.h4` +export const Title = styled.h4` font-size: 14px; font-weight: 500; line-height: 24px; @@ -54,7 +54,7 @@ const Title = styled.h4` color: #1f2937; margin: 0px; `; -const Price = styled.div` +export const Price = styled.div` font-size: 16px; font-weight: 700; line-height: 26px; @@ -64,7 +64,7 @@ const Price = styled.div` margin-bottom: 6px; `; -const FavoriteCount = styled.span` +export const FavoriteCount = styled.span` color: #4b5563; font-size: 12px; font-weight: 500; @@ -72,12 +72,12 @@ const FavoriteCount = styled.span` text-align: left; `; -const ProductImg = styled.img` +export const ProductImg = styled.img` width: 100%; height: ${({ device, value }) => ByDevice[value][device].height || "auto"}; `; -const ItemListStyle = styled.ul` +export const ItemListStyle = styled.ul` margin: 24px auto; padding: 0px; width: ${({ device, value }) => ByDevice[value][device].ulWidth}; @@ -89,7 +89,7 @@ const ItemListStyle = styled.ul` grid-auto-rows: ${({ value, device }) => ByDevice[value][device].gridRow}; `; -const Item = styled.div` +export const Item = styled.div` display: flex; height: 317px; flex-direction: column; diff --git "a/src/pages/\bItemsPage/ItemsPage.jsx" "b/src/pages/\bItemsPage/ItemsPage.jsx" index ebd73464..00f44cdd 100644 --- "a/src/pages/\bItemsPage/ItemsPage.jsx" +++ "b/src/pages/\bItemsPage/ItemsPage.jsx" @@ -1,7 +1,7 @@ import { useEffect, useState } from "react"; import { Link } from "react-router-dom"; // -import * as S from "./HomePage.style"; +import * as S from "./ItemsPage.style"; import ItemsList from "../../components/ItemsList/ItemsList"; import { getProducts, bestProducts } from "../../api/product.api"; import PageCount from "../../components/pageCount"; diff --git a/src/style/globalStyle.js b/src/style/globalStyle.js new file mode 100644 index 00000000..210b8ed7 --- /dev/null +++ b/src/style/globalStyle.js @@ -0,0 +1,42 @@ +import { createGlobalStyle } from "styled-components"; + +const GlobalStyle = createGlobalStyle` + * { + box-sizing: border-box; + } + body { + font-family: 'Pretendard', sans-serif; + font-display: swap; + margin: 0; + padding: 0; + } + html { + margin: 0; + padding: 0; + } + a { + text-decoration: none; + color: #ffffff; + } + p{ + margin: 0px; + } + @font-face { + font-family: 'Pretendard'; + src: url('https://fastly.jsdelivr.net/gh/Project-Noonnu/noonfonts_2107@1.1/Pretendard-Regular.woff2') format('woff2'); + src: url('https://fastly.jsdelivr.net/gh/Project-Noonnu/noonfonts_2107@1.1/Pretendard-Regular.woff') format('woff'); + font-display: swap; + font-weight: 400; + font-style: normal; +} + +@font-face { +font-family: "Pretendard"; +src: url('https://fastly.jsdelivr.net/gh/Project-Noonnu/noonfonts_2107@1.1/Pretendard-Bold.woff2') format('woff2'); +src: url('https://fastly.jsdelivr.net/gh/Project-Noonnu/noonfonts_2107@1.1/Pretendard-Bold.woff') format('woff'); + font-display: swap; + font-weight: 600; + font-style: normal; +}`; + +export default GlobalStyle; From 86e69a5fbc1999803f9f0a6da311d624b057fb56 Mon Sep 17 00:00:00 2001 From: nerte Date: Wed, 19 Feb 2025 16:25:26 +0900 Subject: [PATCH 04/38] =?UTF-8?q?[Refactor]=20ItemsPage=20mobile=20?= =?UTF-8?q?=EB=B0=98=EC=9D=91=ED=98=95=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/assets/icons/search.icon.svg | 3 + src/assets/icons/sort.icon.svg | 6 ++ src/components/ItemsList/ItemsList.jsx | 5 +- src/components/ItemsList/ItemsList.style.jsx | 9 +- .../common/BtnHeart/BtnHeart.style.jsx | 1 - src/components/common/Button/Button.jsx | 36 ++------ src/components/common/Button/Button.style.jsx | 2 +- src/components/common/Input/Input.jsx | 17 ++-- src/components/common/Input/Input.style.jsx | 28 ++++++- src/components/common/Select/Select.jsx | 20 +++-- src/components/common/Select/Select.style.jsx | 26 ++++-- "src/pages/\bItemsPage/ItemsPage.jsx" | 83 ++++++++++++++----- "src/pages/\bItemsPage/ItemsPage.style.jsx" | 83 ++++++++++++------- src/style/globalStyle.js | 5 ++ 14 files changed, 208 insertions(+), 116 deletions(-) create mode 100644 src/assets/icons/search.icon.svg create mode 100644 src/assets/icons/sort.icon.svg diff --git a/src/assets/icons/search.icon.svg b/src/assets/icons/search.icon.svg new file mode 100644 index 00000000..d9cc31ea --- /dev/null +++ b/src/assets/icons/search.icon.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/icons/sort.icon.svg b/src/assets/icons/sort.icon.svg new file mode 100644 index 00000000..657b44f9 --- /dev/null +++ b/src/assets/icons/sort.icon.svg @@ -0,0 +1,6 @@ + + + + + + diff --git a/src/components/ItemsList/ItemsList.jsx b/src/components/ItemsList/ItemsList.jsx index 6f7499e6..909ff1b5 100644 --- a/src/components/ItemsList/ItemsList.jsx +++ b/src/components/ItemsList/ItemsList.jsx @@ -21,9 +21,8 @@ function ListItem({ value, items }) {
    {items.name} {items.price} 원 -
    - -
    + +
    ); diff --git a/src/components/ItemsList/ItemsList.style.jsx b/src/components/ItemsList/ItemsList.style.jsx index fffd3dcd..24ddb97e 100644 --- a/src/components/ItemsList/ItemsList.style.jsx +++ b/src/components/ItemsList/ItemsList.style.jsx @@ -7,21 +7,18 @@ const ByDevice = { gridTemplate: "repeat(1, 343px)", gridRow: "434px", height: "343px", - ulWidth: "343px", }, tablet: { gap: "10px", gridTemplate: "repeat(3, 343px)", gridRow: "434px", height: "343px", - ulWidth: "696px", }, desktop: { gap: "24px", gridTemplate: "repeat(4, 282px)", gridRow: "378px", height: "282px", - ulWidth: "1200px", }, }, products: { @@ -30,19 +27,16 @@ const ByDevice = { gridTemplate: "repeat(2, 168px)", gridRow: "343px", height: "168px", - ulWidth: "343px", }, tablet: { gap: "40px 24px", gridTemplate: "repeat(3, 221px)", height: "221px", - ulWidth: "696px", }, desktop: { gap: "40px 24px", gridTemplate: "repeat(5, 221px)", height: "221px", - ulWidth: "1200px", }, }, }; @@ -73,14 +67,13 @@ export const FavoriteCount = styled.span` `; export const ProductImg = styled.img` - width: 100%; + aspect-ratio: 1/1; height: ${({ device, value }) => ByDevice[value][device].height || "auto"}; `; export const ItemListStyle = styled.ul` margin: 24px auto; padding: 0px; - width: ${({ device, value }) => ByDevice[value][device].ulWidth}; display: grid; list-style: none; gap: ${({ device, value }) => ByDevice[value][device].gap}; diff --git a/src/components/common/BtnHeart/BtnHeart.style.jsx b/src/components/common/BtnHeart/BtnHeart.style.jsx index 78db533a..66ab1a9f 100644 --- a/src/components/common/BtnHeart/BtnHeart.style.jsx +++ b/src/components/common/BtnHeart/BtnHeart.style.jsx @@ -14,7 +14,6 @@ export const InactiveBtnHeart = styled.button` font-weight: 500; font-size: 16px; line-height: 26px; - background: ${theme.color.white}; color: ${theme.color.gray500}; ${(props) => diff --git a/src/components/common/Button/Button.jsx b/src/components/common/Button/Button.jsx index 17e28380..83f58541 100644 --- a/src/components/common/Button/Button.jsx +++ b/src/components/common/Button/Button.jsx @@ -1,39 +1,13 @@ import * as S from "./Button.style"; // //버튼 컨테이너 필요 -export default function Button({ onClick, ...props }) { - const { - $small, - medium, - value, - toggle, - square, - circle, - heart, - children, - disabled, - ...rest - } = props; - //...rest: $square,$small,$medium,toggle,$circle,children,disabled - const onClickChange = (e) => { - onClick(e); - }; +export default function Button({ onClick, children, ...props }) { + const { value, square, ...rest } = props; return ( <> - {toggle ? ( - + + + + {}} + /> + + + + ) : ( + + 전체 상품 + + + {}} + /> + + + + + + + + + )} + + + + + ); } diff --git "a/src/pages/\bItemsPage/ItemsPage.style.jsx" "b/src/pages/\bItemsPage/ItemsPage.style.jsx" index 57633dec..87641d89 100644 --- "a/src/pages/\bItemsPage/ItemsPage.style.jsx" +++ "b/src/pages/\bItemsPage/ItemsPage.style.jsx" @@ -1,46 +1,71 @@ import styled from "styled-components"; - +import theme from "../../style/theme"; +// +export const Background = styled.div` + width: 100%; + @media (max-width: 375px) { + padding: 16px; + } + @media (min-width: 376px) and (max-width: 768px) { + padding: 24px; + } +`; export const Contents = styled.div` - width: ${({ device }) => - device === "desktop" ? "1200px" : device === "tablet" ? "696px" : "344px"}; - margin: 70px auto; + width: 100%; `; -export const InputDiv = styled.div` + +export const Title = styled.h3` + font: ${theme.font.H3Bold}; + @media (max-width: 375px) { + width: 74px; + height: 32px; + } +`; +export const TitleInputDiv = styled.div` display: flex; justify-content: space-between; width: 100%; - margin: 0 auto; - flex-wrap: wrap; - gap: 12px; + @media (max-width: 375px) { + flex: 0 1 calc(50% - 10px); + } `; -export const SearchBtn = styled.button` +export const InputDiv = styled.div` + display: flex; + gap: 12px; + height: auto; +`; +export const SearchBtnContainer = styled.div` + width: 133px; height: 42px; - padding: 12px 23px; - border-radius: 8px; - color: #f3f4f6; - background-color: #3692ff; - border: none; - font-size: 16px; - font-weight: 600; - line-height: 26px; - order: ${({ device }) => (device === "mobile" ? 1 : "auto")}; + font: ${theme.font.H5Bold}; + @media (max-width: 375px) { + } `; -export const InputForm = styled.input` +export const InputContainer = styled.div` width: ${({ device }) => device === "desktop" ? "325px" : device === "tablet" ? "242px" : "288px"}; - height: 42px; - padding: 9px 20px 9px 16px; - border-radius: 12px; - border: none; - background-color: #f3f4f6; - color: #9ca3af; - font-size: 16px; - font-weight: 400; - line-height: 26px; text-align: left; - order: ${({ device }) => (device === "mobile" ? 2 : "auto")}; margin-left: ${({ device }) => device === "desktop" ? "500px" : device === "tablet" ? "80px" : "0px"}; + @media (max-width: 375px) { + order: 1; + } +`; + +export const MobileContainer = styled.div` + display: flex; + flex-direction: column; + gap: 8px; +`; + +export const MobileTitleBtn = styled.div` + display: flex; + justify-content: space-between; +`; + +export const SearchSelectContainer = styled.div` + display: flex; + justify-content: space-between; `; diff --git a/src/style/globalStyle.js b/src/style/globalStyle.js index 210b8ed7..2ed7dd51 100644 --- a/src/style/globalStyle.js +++ b/src/style/globalStyle.js @@ -3,6 +3,7 @@ import { createGlobalStyle } from "styled-components"; const GlobalStyle = createGlobalStyle` * { box-sizing: border-box; + margin: 0px; } body { font-family: 'Pretendard', sans-serif; @@ -14,6 +15,7 @@ const GlobalStyle = createGlobalStyle` margin: 0; padding: 0; } + a { text-decoration: none; color: #ffffff; @@ -21,6 +23,9 @@ const GlobalStyle = createGlobalStyle` p{ margin: 0px; } + button { + padding: 0px + } @font-face { font-family: 'Pretendard'; src: url('https://fastly.jsdelivr.net/gh/Project-Noonnu/noonfonts_2107@1.1/Pretendard-Regular.woff2') format('woff2'); From 930dba9fb5b23a616dd78a7a17723f9b5274ee7a Mon Sep 17 00:00:00 2001 From: nerte Date: Wed, 19 Feb 2025 16:35:40 +0900 Subject: [PATCH 05/38] =?UTF-8?q?[Style]=20=EC=9D=B4=EC=A0=84=20=EC=9E=91?= =?UTF-8?q?=EC=97=85=20style.jsx=20font=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/ItemsList/ItemsList.jsx | 2 -- src/components/ItemsList/ItemsList.style.jsx | 21 +++++++------------- src/pages/AddItem/AddItem.style.jsx | 7 +++---- src/style/theme.jsx | 6 +++--- 4 files changed, 13 insertions(+), 23 deletions(-) diff --git a/src/components/ItemsList/ItemsList.jsx b/src/components/ItemsList/ItemsList.jsx index 909ff1b5..3d5b6655 100644 --- a/src/components/ItemsList/ItemsList.jsx +++ b/src/components/ItemsList/ItemsList.jsx @@ -17,11 +17,9 @@ function ListItem({ value, items }) { src={items.images[0]} alt="이미지" /> -
    {items.name} {items.price} 원 -
    diff --git a/src/components/ItemsList/ItemsList.style.jsx b/src/components/ItemsList/ItemsList.style.jsx index 24ddb97e..9ab31ddb 100644 --- a/src/components/ItemsList/ItemsList.style.jsx +++ b/src/components/ItemsList/ItemsList.style.jsx @@ -1,5 +1,5 @@ import styled from "styled-components"; - +import theme from "../../style/theme"; const ByDevice = { best: { mobile: { @@ -41,28 +41,21 @@ const ByDevice = { }, }; export const Title = styled.h4` - font-size: 14px; - font-weight: 500; - line-height: 24px; + font: ${theme.font.H7Medium}; text-align: left; - color: #1f2937; - margin: 0px; + color: ${theme.color.gray800}; `; export const Price = styled.div` - font-size: 16px; - font-weight: 700; - line-height: 26px; + font: ${theme.font.H5Bold}; text-align: left; - color: #1f2937; + color: ${theme.color.gray800}; margin-top: 6px; margin-bottom: 6px; `; export const FavoriteCount = styled.span` - color: #4b5563; - font-size: 12px; - font-weight: 500; - line-height: 18px; + color: ${theme.color.gray600}; + font: ${theme.font.H8}; text-align: left; `; diff --git a/src/pages/AddItem/AddItem.style.jsx b/src/pages/AddItem/AddItem.style.jsx index 0fe592a5..a077cb7e 100644 --- a/src/pages/AddItem/AddItem.style.jsx +++ b/src/pages/AddItem/AddItem.style.jsx @@ -1,5 +1,6 @@ import styled from "styled-components"; - +import theme from "../../style/theme"; +// export const Background = styled.div` width: 100%; margin: 0; @@ -34,9 +35,7 @@ export const FlexDiv = styled.div` width: 100%; `; export const Title = styled.p` - font-weight: 700; - font-size: 20px; - line-height: 32px; + font: ${theme.font.H3Bold}; margin-top: 5px; margin-bottom: 5px; `; diff --git a/src/style/theme.jsx b/src/style/theme.jsx index b9d2a023..81e2cd49 100644 --- a/src/style/theme.jsx +++ b/src/style/theme.jsx @@ -18,10 +18,10 @@ const theme = { font: { //weight , size , height , fontfamily H1: "600 40px/47px 'Pretendard', sans-serif", - H2Bold: "600 24px/32px 'Pretendard', sans-serif", + H2Bold: "600 24px/36px 'Pretendard', sans-serif", H2Regular: "400 24px/36px 'Pretendard', sans-serif", - H3Bold: "600 20px/30px 'Pretendard', sans-serif", - H3Regular: "400 20px/30px 'Pretendard', sans-serif", + H3Bold: "600 20px/32px 'Pretendard', sans-serif", + H3Regular: "400 20px/32px 'Pretendard', sans-serif", H4Bold: "600 18px/28px 'Pretendard', sans-serif", H4Regular: "400 18px/28px 'Pretendard', sans-serif", H5Bold: "600 16px/26px 'Pretendard', sans-serif", From addb51f267cfe0141edfd3225db7eb3d4022ebed Mon Sep 17 00:00:00 2001 From: nerte Date: Wed, 19 Feb 2025 16:46:48 +0900 Subject: [PATCH 06/38] [Refactor] edit heartBtn --- src/components/ItemsList/ItemsList.jsx | 2 +- src/components/common/BtnHeart/BtnHeart.jsx | 23 ++++--------------- .../common/BtnHeart/BtnHeart.style.jsx | 17 +++++++++++--- src/components/common/Select/Select.jsx | 6 ++--- src/pages/ProductPage/ProductInfo.jsx | 2 +- 5 files changed, 24 insertions(+), 26 deletions(-) diff --git a/src/components/ItemsList/ItemsList.jsx b/src/components/ItemsList/ItemsList.jsx index 3d5b6655..a55761d3 100644 --- a/src/components/ItemsList/ItemsList.jsx +++ b/src/components/ItemsList/ItemsList.jsx @@ -20,7 +20,7 @@ function ListItem({ value, items }) {
    {items.name} {items.price} 원 - +
    ); diff --git a/src/components/common/BtnHeart/BtnHeart.jsx b/src/components/common/BtnHeart/BtnHeart.jsx index 4ee40f3e..f19fba9e 100644 --- a/src/components/common/BtnHeart/BtnHeart.jsx +++ b/src/components/common/BtnHeart/BtnHeart.jsx @@ -4,30 +4,17 @@ import inactiveHeart from "../../../assets/icons/inactive.heart.icon.svg"; import * as S from "./BtnHeart.style"; // export default function BtnHeart({ value, ...props }) { - const { border, active, onClick, small, ...rest } = props; - const onClickChange = (e) => { - onClick(e); - }; + const { active, ...rest } = props; return ( <> {active ? ( - - + + {value} ) : ( - - + + {value} )} diff --git a/src/components/common/BtnHeart/BtnHeart.style.jsx b/src/components/common/BtnHeart/BtnHeart.style.jsx index 66ab1a9f..ae6032f0 100644 --- a/src/components/common/BtnHeart/BtnHeart.style.jsx +++ b/src/components/common/BtnHeart/BtnHeart.style.jsx @@ -11,9 +11,7 @@ export const InactiveBtnHeart = styled.button` height: 40px; border: none; border-radius: 35px; - font-weight: 500; - font-size: 16px; - line-height: 26px; + font: ${theme.font.H5Regular}; background: ${theme.color.white}; color: ${theme.color.gray500}; ${(props) => @@ -27,6 +25,13 @@ export const InactiveBtnHeart = styled.button` css` border: 1px solid ${theme.color.gray200}; `}; + ${(props) => + props.$items && + css` + font: ${theme.font.H8}; + width: 42px; + height: 19px; + `}; `; export const ActiveBtnHeart = styled.button` @@ -66,4 +71,10 @@ export const HeartImg = styled.img` width: 20px; height: 17px; `} + ${(props) => + props.$items && + css` + width: 16px; + height: 16px; + `} `; diff --git a/src/components/common/Select/Select.jsx b/src/components/common/Select/Select.jsx index 7e5fa0e0..3eaf0271 100644 --- a/src/components/common/Select/Select.jsx +++ b/src/components/common/Select/Select.jsx @@ -22,15 +22,15 @@ export function SortSelect({ onChange, ...props }) { return ( <> - + {device === "mobile" ? ( setIsOpen(!isOpen)}> - + ) : ( setIsOpen(!isOpen)}> {selected} - + 정렬 )} diff --git a/src/pages/ProductPage/ProductInfo.jsx b/src/pages/ProductPage/ProductInfo.jsx index f3089b26..c92eebd7 100644 --- a/src/pages/ProductPage/ProductInfo.jsx +++ b/src/pages/ProductPage/ProductInfo.jsx @@ -62,7 +62,7 @@ export default function ProductInfo({ productId }) { - + From fecbd643aba3483a6704bddd18e4ec807bf346a9 Mon Sep 17 00:00:00 2001 From: nerte Date: Wed, 19 Feb 2025 19:20:59 +0900 Subject: [PATCH 07/38] [Refactor]edit pageCount --- src/assets/icons/nextPage.icon.svg | 3 + src/assets/icons/previousPage.icon.svg | 3 + src/components/ItemsList/ItemsList.jsx | 29 ++++----- src/components/ItemsList/ItemsList.style.jsx | 52 ++++++++-------- src/components/PageNation/pageCount.jsx | 50 +++++++++++++++ src/components/PageNation/pageCount.style.jsx | 42 +++++++++++++ src/components/common/Button/Button.style.jsx | 4 +- src/components/common/Select/Select.jsx | 11 +++- src/components/pageCount.js | 61 ------------------- "src/pages/\bItemsPage/ItemsPage.jsx" | 31 ++++------ "src/pages/\bItemsPage/ItemsPage.style.jsx" | 23 +++---- src/style/globalStyle.js | 5 ++ 12 files changed, 169 insertions(+), 145 deletions(-) create mode 100644 src/assets/icons/nextPage.icon.svg create mode 100644 src/assets/icons/previousPage.icon.svg create mode 100644 src/components/PageNation/pageCount.jsx create mode 100644 src/components/PageNation/pageCount.style.jsx delete mode 100644 src/components/pageCount.js diff --git a/src/assets/icons/nextPage.icon.svg b/src/assets/icons/nextPage.icon.svg new file mode 100644 index 00000000..368742c9 --- /dev/null +++ b/src/assets/icons/nextPage.icon.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/assets/icons/previousPage.icon.svg b/src/assets/icons/previousPage.icon.svg new file mode 100644 index 00000000..040e81c2 --- /dev/null +++ b/src/assets/icons/previousPage.icon.svg @@ -0,0 +1,3 @@ + + + diff --git a/src/components/ItemsList/ItemsList.jsx b/src/components/ItemsList/ItemsList.jsx index a55761d3..d5f4b82e 100644 --- a/src/components/ItemsList/ItemsList.jsx +++ b/src/components/ItemsList/ItemsList.jsx @@ -13,32 +13,27 @@ function ListItem({ value, items }) { navigate(`./${items.id}`)}> -
    + {items.name} {items.price} 원 -
    +
    ); } -export default function ItemsList({ value, items, device }) { +export default function ItemsList({ value, items, ...props }) { + const device = useWindowSize(); return ( -
    -
    - - {items.map((item) => { - return ( -
  • - -
  • - ); - })} -
    -
    -
    + + {items.map((item) => { + return ( + + ); + })} + ); } diff --git a/src/components/ItemsList/ItemsList.style.jsx b/src/components/ItemsList/ItemsList.style.jsx index 9ab31ddb..f4788c0c 100644 --- a/src/components/ItemsList/ItemsList.style.jsx +++ b/src/components/ItemsList/ItemsList.style.jsx @@ -25,21 +25,39 @@ const ByDevice = { mobile: { gap: "32px 8px", gridTemplate: "repeat(2, 168px)", - gridRow: "343px", + gridRow: "264px", height: "168px", }, tablet: { gap: "40px 24px", gridTemplate: "repeat(3, 221px)", height: "221px", + gridRow: "317px", }, desktop: { gap: "40px 24px", gridTemplate: "repeat(5, 221px)", height: "221px", + gridRow: "317px", }, }, }; +export const Item = styled.div` + width: 100%; + display: flex; + flex-direction: column; + gap: 16px; +`; +export const ProductImg = styled.img` + aspect-ratio: 1/1; + height: ${({ $device, value }) => ByDevice[value][$device].height || "auto"}; +`; + +export const FlexContent = styled.div` + display: flex; + flex-direction: column; + gap: 6px; +`; export const Title = styled.h4` font: ${theme.font.H7Medium}; text-align: left; @@ -49,35 +67,13 @@ export const Price = styled.div` font: ${theme.font.H5Bold}; text-align: left; color: ${theme.color.gray800}; - margin-top: 6px; - margin-bottom: 6px; `; -export const FavoriteCount = styled.span` - color: ${theme.color.gray600}; - font: ${theme.font.H8}; - text-align: left; -`; - -export const ProductImg = styled.img` - aspect-ratio: 1/1; - height: ${({ device, value }) => ByDevice[value][device].height || "auto"}; -`; - -export const ItemListStyle = styled.ul` +export const ItemListStyle = styled.div` margin: 24px auto; - padding: 0px; display: grid; - list-style: none; - gap: ${({ device, value }) => ByDevice[value][device].gap}; - grid-template-columns: ${({ device, value }) => - ByDevice[value][device].gridTemplate}; - grid-auto-rows: ${({ value, device }) => ByDevice[value][device].gridRow}; -`; - -export const Item = styled.div` - display: flex; - height: 317px; - flex-direction: column; - gap: 16px; + gap: ${({ $device, value }) => ByDevice[value][$device].gap}; + grid-template-columns: ${({ $device, value }) => + ByDevice[value][$device].gridTemplate}; + grid-auto-rows: ${({ value, $device }) => ByDevice[value][$device].gridRow}; `; diff --git a/src/components/PageNation/pageCount.jsx b/src/components/PageNation/pageCount.jsx new file mode 100644 index 00000000..8e74949a --- /dev/null +++ b/src/components/PageNation/pageCount.jsx @@ -0,0 +1,50 @@ +import { useState } from "react"; +import * as S from "./pageCount.style"; +import previousIcon from "../../assets/icons/previousPage.icon.svg"; +import nextIcon from "../../assets/icons/nextPage.icon.svg"; +// +export function PageButton({ page, value, onClick }) { + return ( + + {value} + + ); +} +function PageCount({ page, onClick }) { + const BtnArray = [1, 2, 3, 4, 5]; + const [currentPage, setCurrentPage] = useState(1); + const handleClickBtn = (e) => { + const currentPage = e.target.value; + setCurrentPage(currentPage); + onClick(currentPage); + }; + const handleClickPrev = () => { + setCurrentPage(currentPage - 1); + onClick(currentPage - 1); + }; + const handleClickNext = () => { + setCurrentPage(currentPage + 1); + onClick(currentPage + 1); + }; + return ( + + + 이전 + + {BtnArray.map((btn) => { + return ( + + ); + })} + + 다음 + + + ); +} +export default PageCount; diff --git a/src/components/PageNation/pageCount.style.jsx b/src/components/PageNation/pageCount.style.jsx new file mode 100644 index 00000000..75fa5e68 --- /dev/null +++ b/src/components/PageNation/pageCount.style.jsx @@ -0,0 +1,42 @@ +import styled from "styled-components"; +import theme from "../../style/theme"; + +export const PageBtn = styled.div` + display: flex; + gap: 4px; + margin: 43px auto 58px; + text-align: center; + width: 304px; +`; + +export const Btn = styled.button` + width: 40px; + height: 40px; + border-radius: 40px; + border: 1px solid ${theme.color.gray200}; + opacity: 0px; + font-size: 16px; + font-weight: 600; + line-height: 26px; + background-color: ${({ page, value }) => + page === value ? "#2f80ed" : "#ffffff"}; + color: ${({ page, value }) => (page === value ? "#f9fafb" : "#6b7280")}; + + &:active { + background-color: ${theme.color.blue}; + color: ${theme.color.gray50}; + } + + &:hover { + background-color: ${theme.color.blue}; + color: ${theme.color.gray50}; + } +`; +export const NextPrevBtn = styled.button` + width: 40px; + height: 40px; + border-radius: 40px; + border: 1px solid ${theme.color.gray200}; + + background-color: ${theme.color.white}; +`; diff --git a/src/components/common/Button/Button.style.jsx b/src/components/common/Button/Button.style.jsx index 1b033926..1c1f4dc0 100644 --- a/src/components/common/Button/Button.style.jsx +++ b/src/components/common/Button/Button.style.jsx @@ -10,9 +10,7 @@ export const Button = styled.button` height: 100%; border-radius: 8px; border: none; - font-size: 16px; - line-height: 26px; - font-weight: 600px; + font: ${theme.font.H5Bold}; color: ${theme.color.gray100}; background-color: ${theme.color.blue}; diff --git a/src/components/common/Select/Select.jsx b/src/components/common/Select/Select.jsx index 3eaf0271..c205338e 100644 --- a/src/components/common/Select/Select.jsx +++ b/src/components/common/Select/Select.jsx @@ -5,10 +5,11 @@ import kebabIcon from "../../../assets/icons/kebab.icon.svg"; import sortIcon from "../../../assets/icons/sort.icon.svg"; import { useAutoClose } from "../../../hooks/useAutoClose"; import { button } from "../../../constants/globalConstant"; +import useWindowSize from "../../../hooks/useWindowSize"; // export function SortSelect({ onChange, ...props }) { - const { device, ...rest } = props; + const device = useWindowSize(); const options = ["최신순", "좋아요순"]; const [selected, setSelected] = useState("최신순"); @@ -22,7 +23,7 @@ export function SortSelect({ onChange, ...props }) { return ( <> - + {device === "mobile" ? ( setIsOpen(!isOpen)}> @@ -61,7 +62,11 @@ export function EditSelect({ onChange, ...props }) { return ( <> - setIsOpen(!isOpen)}> + setIsOpen(!isOpen)} + {...props} + > 케밥 diff --git a/src/components/pageCount.js b/src/components/pageCount.js deleted file mode 100644 index 2d1ab579..00000000 --- a/src/components/pageCount.js +++ /dev/null @@ -1,61 +0,0 @@ -import styled from "styled-components"; - -const PageBtn = styled.div` - display: flex; - gap: 4px; - margin: 43px auto 58px; - text-align: center; - width: 304px; -`; - -const Btn = styled.button` - width: 40px; - height: 40px; - border-radius: 40px; - border: 1px solid #e5e7eb; - opacity: 0px; - font-size: 16px; - font-weight: 600; - line-height: 26px; - background-color: ${({ page, value }) => - page === value ? "#2f80ed" : "#ffffff"}; - color: ${({ page, value }) => (page === value ? "#f9fafb" : "#6b7280")}; - - &:active { - background-color: #2f80ed; - color: #f9fafb; - } - - &:hover { - background-color: #2f80ed; - color: #f9fafb; - } -`; - -export function PageButton({ page, value, onClick }) { - return ( - - {value} - - ); -} -function PageCount({ page, onClick }) { - const BtnArray = ["<", 1, 2, 3, 4, 5, ">"]; - const handleClickBtn = (e) => { - const currentPage = e.target.value; - onClick(currentPage); - }; - - return ( - - {BtnArray.map((btn) => { - return ( -
  • - -
  • - ); - })} -
    - ); -} -export default PageCount; diff --git "a/src/pages/\bItemsPage/ItemsPage.jsx" "b/src/pages/\bItemsPage/ItemsPage.jsx" index 6d8eaf1c..2e2e76ab 100644 --- "a/src/pages/\bItemsPage/ItemsPage.jsx" +++ "b/src/pages/\bItemsPage/ItemsPage.jsx" @@ -4,7 +4,7 @@ import { useNavigate } from "react-router-dom"; import * as S from "./ItemsPage.style"; import ItemsList from "../../components/ItemsList/ItemsList"; import { getProducts, bestProducts } from "../../api/product.api"; -import PageCount from "../../components/pageCount"; +import PageCount from "../../components/PageNation/pageCount"; import useWindowSize from "../../hooks/useWindowSize"; import { SortSelect } from "../../components/common/Select/Select"; import Button from "../../components/common/Button/Button"; @@ -19,9 +19,8 @@ function HomePage() { const device = useWindowSize(); const navigate = useNavigate(); // - const handleChangeSort = (selected) => { - const { label } = selected; - setSelectedOrder(label); + const handleChangeSort = (option) => { + setSelectedOrder(option); }; const handleLoad = async (options) => { @@ -41,16 +40,16 @@ function HomePage() { return ( - +
    베스트 상품 - +
    {device === "mobile" ? ( 전체 상품 - + @@ -61,15 +60,11 @@ function HomePage() { placeholder="검색할 상품을 입력해주세요" onChange={() => {}} /> - + ) : ( - + 전체 상품 @@ -78,22 +73,18 @@ function HomePage() { onChange={() => {}} /> - + - + )} - +
    diff --git "a/src/pages/\bItemsPage/ItemsPage.style.jsx" "b/src/pages/\bItemsPage/ItemsPage.style.jsx" index 87641d89..d203b696 100644 --- "a/src/pages/\bItemsPage/ItemsPage.style.jsx" +++ "b/src/pages/\bItemsPage/ItemsPage.style.jsx" @@ -3,6 +3,9 @@ import theme from "../../style/theme"; // export const Background = styled.div` width: 100%; + display: flex; + justify-content: center; + align-items: center; @media (max-width: 375px) { padding: 16px; } @@ -17,7 +20,7 @@ export const Contents = styled.div` export const Title = styled.h3` font: ${theme.font.H3Bold}; @media (max-width: 375px) { - width: 74px; + width: 92px; height: 32px; } `; @@ -25,12 +28,10 @@ export const TitleInputDiv = styled.div` display: flex; justify-content: space-between; width: 100%; - @media (max-width: 375px) { - flex: 0 1 calc(50% - 10px); - } `; export const InputDiv = styled.div` + width: 100%; display: flex; gap: 12px; height: auto; @@ -38,19 +39,15 @@ export const InputDiv = styled.div` export const SearchBtnContainer = styled.div` width: 133px; height: 42px; - font: ${theme.font.H5Bold}; - @media (max-width: 375px) { - } `; export const InputContainer = styled.div` - width: ${({ device }) => - device === "desktop" ? "325px" : device === "tablet" ? "242px" : "288px"}; - text-align: left; - margin-left: ${({ device }) => - device === "desktop" ? "500px" : device === "tablet" ? "80px" : "0px"}; + width: 325px; @media (max-width: 375px) { - order: 1; + width: 288px; + } + @media (min-width: 376px) and (max-width: 768px) { + width: 242px; } `; diff --git a/src/style/globalStyle.js b/src/style/globalStyle.js index 2ed7dd51..65ce3cd6 100644 --- a/src/style/globalStyle.js +++ b/src/style/globalStyle.js @@ -4,6 +4,7 @@ const GlobalStyle = createGlobalStyle` * { box-sizing: border-box; margin: 0px; + padding: 0px; } body { font-family: 'Pretendard', sans-serif; @@ -26,6 +27,10 @@ const GlobalStyle = createGlobalStyle` button { padding: 0px } + ul{ + list-style: none; + + } @font-face { font-family: 'Pretendard'; src: url('https://fastly.jsdelivr.net/gh/Project-Noonnu/noonfonts_2107@1.1/Pretendard-Regular.woff2') format('woff2'); From f8d651c7d4ffcb319544590561b656e17a90612f Mon Sep 17 00:00:00 2001 From: nerte Date: Thu, 20 Feb 2025 15:06:37 +0900 Subject: [PATCH 08/38] [Style]ItemList style edit --- src/components/ItemsList/ItemsList.jsx | 6 +- src/components/ItemsList/ItemsList.style.jsx | 1 + src/components/PageNation/pageCount.jsx | 2 + src/components/PageNation/pageCount.style.jsx | 1 - "src/pages/\bItemsPage/ItemsPage.jsx" | 84 ++++++++++--------- "src/pages/\bItemsPage/ItemsPage.style.jsx" | 5 ++ 6 files changed, 54 insertions(+), 45 deletions(-) diff --git a/src/components/ItemsList/ItemsList.jsx b/src/components/ItemsList/ItemsList.jsx index d5f4b82e..f1cf61b5 100644 --- a/src/components/ItemsList/ItemsList.jsx +++ b/src/components/ItemsList/ItemsList.jsx @@ -3,9 +3,7 @@ import useWindowSize from "../../hooks/useWindowSize"; // import * as S from "./ItemsList.style"; import BtnHeart from "../common/BtnHeart/BtnHeart"; - // - function ListItem({ value, items }) { const navigate = useNavigate(); const device = useWindowSize(); @@ -25,10 +23,12 @@ function ListItem({ value, items }) { ); } +// export default function ItemsList({ value, items, ...props }) { const device = useWindowSize(); + return ( - + {items.map((item) => { return ( diff --git a/src/components/ItemsList/ItemsList.style.jsx b/src/components/ItemsList/ItemsList.style.jsx index f4788c0c..8c18563a 100644 --- a/src/components/ItemsList/ItemsList.style.jsx +++ b/src/components/ItemsList/ItemsList.style.jsx @@ -51,6 +51,7 @@ export const Item = styled.div` export const ProductImg = styled.img` aspect-ratio: 1/1; height: ${({ $device, value }) => ByDevice[value][$device].height || "auto"}; + border-radius: 16px; `; export const FlexContent = styled.div` diff --git a/src/components/PageNation/pageCount.jsx b/src/components/PageNation/pageCount.jsx index 8e74949a..11fc665d 100644 --- a/src/components/PageNation/pageCount.jsx +++ b/src/components/PageNation/pageCount.jsx @@ -10,6 +10,7 @@ export function PageButton({ page, value, onClick }) { ); } +// function PageCount({ page, onClick }) { const BtnArray = [1, 2, 3, 4, 5]; const [currentPage, setCurrentPage] = useState(1); @@ -26,6 +27,7 @@ function PageCount({ page, onClick }) { setCurrentPage(currentPage + 1); onClick(currentPage + 1); }; + return ( diff --git a/src/components/PageNation/pageCount.style.jsx b/src/components/PageNation/pageCount.style.jsx index 75fa5e68..949a5366 100644 --- a/src/components/PageNation/pageCount.style.jsx +++ b/src/components/PageNation/pageCount.style.jsx @@ -37,6 +37,5 @@ export const NextPrevBtn = styled.button` height: 40px; border-radius: 40px; border: 1px solid ${theme.color.gray200}; - background-color: ${theme.color.white}; `; diff --git "a/src/pages/\bItemsPage/ItemsPage.jsx" "b/src/pages/\bItemsPage/ItemsPage.jsx" index 2e2e76ab..3503c61c 100644 --- "a/src/pages/\bItemsPage/ItemsPage.jsx" +++ "b/src/pages/\bItemsPage/ItemsPage.jsx" @@ -40,53 +40,55 @@ function HomePage() { return ( - -
    - 베스트 상품 - -
    - {device === "mobile" ? ( - - - 전체 상품 - - - - - - {}} - /> - - - - ) : ( - - 전체 상품 - - + + +
    + 베스트 상품 + +
    + {device === "mobile" ? ( + + + 전체 상품 + + + + + {}} /> -
    - - - + + + + ) : ( + + 전체 상품 + + + {}} + /> + + + + - - - - )} + +
    +
    + )} - - -
    + + + +
    ); } diff --git "a/src/pages/\bItemsPage/ItemsPage.style.jsx" "b/src/pages/\bItemsPage/ItemsPage.style.jsx" index d203b696..0494e22c 100644 --- "a/src/pages/\bItemsPage/ItemsPage.style.jsx" +++ "b/src/pages/\bItemsPage/ItemsPage.style.jsx" @@ -6,11 +6,16 @@ export const Background = styled.div` display: flex; justify-content: center; align-items: center; +`; +export const ContentsWrapper = styled.div` + width: 1200px; @media (max-width: 375px) { padding: 16px; + width: 100%; } @media (min-width: 376px) and (max-width: 768px) { padding: 24px; + width: 100%; } `; export const Contents = styled.div` From b87b91b8153d5cc572a90aae4b1731c8f2e67cd9 Mon Sep 17 00:00:00 2001 From: nerte Date: Thu, 20 Feb 2025 15:21:15 +0900 Subject: [PATCH 09/38] [Chore]i typescript and edit tsconfig.json options --- package-lock.json | 49 ++++++++++++++------ package.json | 5 ++ tsconfig.json | 114 ++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 154 insertions(+), 14 deletions(-) create mode 100644 tsconfig.json diff --git a/package-lock.json b/package-lock.json index b37997c1..0c72611e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -21,6 +21,11 @@ "react-select": "^5.9.0", "styled-components": "^6.1.14", "web-vitals": "^2.1.4" + }, + "devDependencies": { + "@types/react": "^19.0.10", + "@types/react-dom": "^19.0.4", + "typescript": "^5.7.3" } }, "node_modules/@adobe/css-tools": { @@ -4572,6 +4577,24 @@ "node": ">=12" } }, + "node_modules/@testing-library/react/node_modules/@types/react": { + "version": "18.3.18", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.18.tgz", + "integrity": "sha512-t4yC+vtgnkYjNSKlFx1jkAhH8LgTo2N/7Qvi83kdEaUtMDiwpbLAktKDaAMlRcJ5eSxZkH74eEGt1ky31d7kfQ==", + "peer": true, + "dependencies": { + "@types/prop-types": "*", + "csstype": "^3.0.2" + } + }, + "node_modules/@testing-library/react/node_modules/@types/react-dom": { + "version": "18.3.5", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.5.tgz", + "integrity": "sha512-P4t6saawp+b/dFrUr2cvkVsfvPguwsxtH6dNIYRllMsefqFzkZk5UIjzyDOv5g1dXIPdG4Sp1yCR4Z6RCUsG/Q==", + "peerDependencies": { + "@types/react": "^18.0.0" + } + }, "node_modules/@testing-library/react/node_modules/aria-query": { "version": "5.1.3", "resolved": "https://registry.npmjs.org/aria-query/-/aria-query-5.1.3.tgz", @@ -4896,21 +4919,20 @@ "integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==" }, "node_modules/@types/react": { - "version": "18.3.18", - "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.18.tgz", - "integrity": "sha512-t4yC+vtgnkYjNSKlFx1jkAhH8LgTo2N/7Qvi83kdEaUtMDiwpbLAktKDaAMlRcJ5eSxZkH74eEGt1ky31d7kfQ==", - "peer": true, + "version": "19.0.10", + "resolved": "https://registry.npmjs.org/@types/react/-/react-19.0.10.tgz", + "integrity": "sha512-JuRQ9KXLEjaUNjTWpzuR231Z2WpIwczOkBEIvbHNCzQefFIT0L8IqE6NV6ULLyC1SI/i234JnDoMkfg+RjQj2g==", "dependencies": { - "@types/prop-types": "*", "csstype": "^3.0.2" } }, "node_modules/@types/react-dom": { - "version": "18.3.5", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.5.tgz", - "integrity": "sha512-P4t6saawp+b/dFrUr2cvkVsfvPguwsxtH6dNIYRllMsefqFzkZk5UIjzyDOv5g1dXIPdG4Sp1yCR4Z6RCUsG/Q==", + "version": "19.0.4", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.0.4.tgz", + "integrity": "sha512-4fSQ8vWFkg+TGhePfUzVmat3eC14TXYSsiiDSLI0dVLsrm9gZFABjPy/Qu6TKgl1tq1Bu1yDsuQgY3A3DOjCcg==", + "dev": true, "peerDependencies": { - "@types/react": "^18.0.0" + "@types/react": "^19.0.0" } }, "node_modules/@types/react-transition-group": { @@ -17882,16 +17904,15 @@ } }, "node_modules/typescript": { - "version": "4.9.5", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", - "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", - "peer": true, + "version": "5.7.3", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.7.3.tgz", + "integrity": "sha512-84MVSjMEHP+FQRPy3pX9sTVV/INIex71s9TL2Gm5FG/WG1SqXeKyZ0k7/blY/4FdOzI12CBy1vGc4og/eus0fw==", "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" }, "engines": { - "node": ">=4.2.0" + "node": ">=14.17" } }, "node_modules/unbox-primitive": { diff --git a/package.json b/package.json index 3fbc0b7a..0732f6c6 100644 --- a/package.json +++ b/package.json @@ -40,5 +40,10 @@ "last 1 firefox version", "last 1 safari version" ] + }, + "devDependencies": { + "@types/react": "^19.0.10", + "@types/react-dom": "^19.0.4", + "typescript": "^5.7.3" } } diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 00000000..b4023d85 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,114 @@ +{ + "compilerOptions": { + /* Visit https://aka.ms/tsconfig to read more about this file */ + + /* Projects */ + // "incremental": true, /* Save .tsbuildinfo files to allow for incremental compilation of projects. */ + // "composite": true, /* Enable constraints that allow a TypeScript project to be used with project references. */ + // "tsBuildInfoFile": "./.tsbuildinfo", /* Specify the path to .tsbuildinfo incremental compilation file. */ + // "disableSourceOfProjectReferenceRedirect": true, /* Disable preferring source files instead of declaration files when referencing composite projects. */ + // "disableSolutionSearching": true, /* Opt a project out of multi-project reference checking when editing. */ + // "disableReferencedProjectLoad": true, /* Reduce the number of projects loaded automatically by TypeScript. */ + + /* Language and Environment */ + "target": "es2016" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */, + // "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */ + // "jsx": "preserve", /* Specify what JSX code is generated. */ + // "experimentalDecorators": true, /* Enable experimental support for legacy experimental decorators. */ + // "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */ + // "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */ + // "jsxFragmentFactory": "", /* Specify the JSX Fragment reference used for fragments when targeting React JSX emit e.g. 'React.Fragment' or 'Fragment'. */ + // "jsxImportSource": "", /* Specify module specifier used to import the JSX factory functions when using 'jsx: react-jsx*'. */ + // "reactNamespace": "", /* Specify the object invoked for 'createElement'. This only applies when targeting 'react' JSX emit. */ + // "noLib": true, /* Disable including any library files, including the default lib.d.ts. */ + // "useDefineForClassFields": true, /* Emit ECMAScript-standard-compliant class fields. */ + // "moduleDetection": "auto", /* Control what method is used to detect module-format JS files. */ + + /* Modules */ + "module": "commonjs" /* Specify what module code is generated. */, + "rootDir": "./src" /* Specify the root folder within your source files. */, + // "moduleResolution": "node10", /* Specify how TypeScript looks up a file from a given module specifier. */ + "baseUrl": "./" /* Specify the base directory to resolve non-relative module names. */, + "paths": { + "@components/*": ["src/components/*"], + "@utils/*": ["src/utils/*"] + } /* Specify a set of entries that re-map imports to additional lookup locations. */, + // "rootDirs": [], /* Allow multiple folders to be treated as one when resolving modules. */ + // "typeRoots": [], /* Specify multiple folders that act like './node_modules/@types'. */ + // "types": [], /* Specify type package names to be included without being referenced in a source file. */ + // "allowUmdGlobalAccess": true, /* Allow accessing UMD globals from modules. */ + // "moduleSuffixes": [], /* List of file name suffixes to search when resolving a module. */ + // "allowImportingTsExtensions": true, /* Allow imports to include TypeScript file extensions. Requires '--moduleResolution bundler' and either '--noEmit' or '--emitDeclarationOnly' to be set. */ + // "rewriteRelativeImportExtensions": true, /* Rewrite '.ts', '.tsx', '.mts', and '.cts' file extensions in relative import paths to their JavaScript equivalent in output files. */ + // "resolvePackageJsonExports": true, /* Use the package.json 'exports' field when resolving package imports. */ + // "resolvePackageJsonImports": true, /* Use the package.json 'imports' field when resolving imports. */ + // "customConditions": [], /* Conditions to set in addition to the resolver-specific defaults when resolving imports. */ + // "noUncheckedSideEffectImports": true, /* Check side effect imports. */ + "resolveJsonModule": true /* Enable importing .json files. */, + // "allowArbitraryExtensions": true, /* Enable importing files with any extension, provided a declaration file is present. */ + // "noResolve": true, /* Disallow 'import's, 'require's or ''s from expanding the number of files TypeScript should add to a project. */ + + /* JavaScript Support */ + "allowJs": true /* Allow JavaScript files to be a part of your program. Use the 'checkJS' option to get errors from these files. */, + // "checkJs": true, /* Enable error reporting in type-checked JavaScript files. */ + // "maxNodeModuleJsDepth": 1, /* Specify the maximum folder depth used for checking JavaScript files from 'node_modules'. Only applicable with 'allowJs'. */ + + /* Emit */ + // "declaration": true, /* Generate .d.ts files from TypeScript and JavaScript files in your project. */ + // "declarationMap": true, /* Create sourcemaps for d.ts files. */ + // "emitDeclarationOnly": true, /* Only output d.ts files and not JavaScript files. */ + "sourceMap": true /* Create source map files for emitted JavaScript files. */, + // "inlineSourceMap": true, /* Include sourcemap files inside the emitted JavaScript. */ + // "noEmit": true, /* Disable emitting files from a compilation. */ + // "outFile": "./", /* Specify a file that bundles all outputs into one JavaScript file. If 'declaration' is true, also designates a file that bundles all .d.ts output. */ + "outDir": "./dist" /* Specify an output folder for all emitted files. */, + // "removeComments": true, /* Disable emitting comments. */ + // "importHelpers": true, /* Allow importing helper functions from tslib once per project, instead of including them per-file. */ + // "downlevelIteration": true, /* Emit more compliant, but verbose and less performant JavaScript for iteration. */ + // "sourceRoot": "", /* Specify the root path for debuggers to find the reference source code. */ + // "mapRoot": "", /* Specify the location where debugger should locate map files instead of generated locations. */ + // "inlineSources": true, /* Include source code in the sourcemaps inside the emitted JavaScript. */ + // "emitBOM": true, /* Emit a UTF-8 Byte Order Mark (BOM) in the beginning of output files. */ + // "newLine": "crlf", /* Set the newline character for emitting files. */ + // "stripInternal": true, /* Disable emitting declarations that have '@internal' in their JSDoc comments. */ + // "noEmitHelpers": true, /* Disable generating custom helper functions like '__extends' in compiled output. */ + // "noEmitOnError": true, /* Disable emitting files if any type checking errors are reported. */ + // "preserveConstEnums": true, /* Disable erasing 'const enum' declarations in generated code. */ + // "declarationDir": "./", /* Specify the output directory for generated declaration files. */ + + /* Interop Constraints */ + // "isolatedModules": true, /* Ensure that each file can be safely transpiled without relying on other imports. */ + // "verbatimModuleSyntax": true, /* Do not transform or elide any imports or exports not marked as type-only, ensuring they are written in the output file's format based on the 'module' setting. */ + // "isolatedDeclarations": true, /* Require sufficient annotation on exports so other tools can trivially generate declaration files. */ + // "allowSyntheticDefaultImports": true, /* Allow 'import x from y' when a module doesn't have a default export. */ + "esModuleInterop": true /* Emit additional JavaScript to ease support for importing CommonJS modules. This enables 'allowSyntheticDefaultImports' for type compatibility. */, + // "preserveSymlinks": true, /* Disable resolving symlinks to their realpath. This correlates to the same flag in node. */ + "forceConsistentCasingInFileNames": true /* Ensure that casing is correct in imports. */, + + /* Type Checking */ + "strict": true /* Enable all strict type-checking options. */, + "noImplicitAny": true /* Enable error reporting for expressions and declarations with an implied 'any' type. */, + // "strictNullChecks": true, /* When type checking, take into account 'null' and 'undefined'. */ + // "strictFunctionTypes": true, /* When assigning functions, check to ensure parameters and the return values are subtype-compatible. */ + // "strictBindCallApply": true, /* Check that the arguments for 'bind', 'call', and 'apply' methods match the original function. */ + // "strictPropertyInitialization": true, /* Check for class properties that are declared but not set in the constructor. */ + // "strictBuiltinIteratorReturn": true, /* Built-in iterators are instantiated with a 'TReturn' type of 'undefined' instead of 'any'. */ + // "noImplicitThis": true, /* Enable error reporting when 'this' is given the type 'any'. */ + // "useUnknownInCatchVariables": true, /* Default catch clause variables as 'unknown' instead of 'any'. */ + // "alwaysStrict": true, /* Ensure 'use strict' is always emitted. */ + // "noUnusedLocals": true, /* Enable error reporting when local variables aren't read. */ + // "noUnusedParameters": true, /* Raise an error when a function parameter isn't read. */ + // "exactOptionalPropertyTypes": true, /* Interpret optional property types as written, rather than adding 'undefined'. */ + // "noImplicitReturns": true, /* Enable error reporting for codepaths that do not explicitly return in a function. */ + // "noFallthroughCasesInSwitch": true, /* Enable error reporting for fallthrough cases in switch statements. */ + // "noUncheckedIndexedAccess": true, /* Add 'undefined' to a type when accessed using an index. */ + // "noImplicitOverride": true, /* Ensure overriding members in derived classes are marked with an override modifier. */ + // "noPropertyAccessFromIndexSignature": true, /* Enforces using indexed accessors for keys declared using an indexed type. */ + // "allowUnusedLabels": true, /* Disable error reporting for unused labels. */ + // "allowUnreachableCode": true, /* Disable error reporting for unreachable code. */ + + /* Completeness */ + // "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */ + "skipLibCheck": true /* Skip type checking all .d.ts files. */ + } +} From 46d3ce6d1b17f9d74b70d5f0940127fe35b62937 Mon Sep 17 00:00:00 2001 From: nerte Date: Thu, 20 Feb 2025 15:39:18 +0900 Subject: [PATCH 10/38] [Chore] i types/styled-compoenents --- package-lock.json | 30 +++++++++++++++---- package.json | 3 +- .../pages/\bItemsPage/ItemsPage.tsx" | 0 3 files changed, 27 insertions(+), 6 deletions(-) rename "src/pages/\bItemsPage/ItemsPage.jsx" => "src/pages/\bItemsPage/ItemsPage.tsx" (100%) diff --git a/package-lock.json b/package-lock.json index 0c72611e..0159a2b6 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,6 +11,7 @@ "@testing-library/jest-dom": "^5.17.0", "@testing-library/react": "^13.4.0", "@testing-library/user-event": "^13.5.0", + "@types/styled-components": "^5.1.34", "axios": "^1.7.9", "firebase": "^11.1.0", "lodash.throttle": "^4.1.1", @@ -25,7 +26,7 @@ "devDependencies": { "@types/react": "^19.0.10", "@types/react-dom": "^19.0.4", - "typescript": "^5.7.3" + "typescript": "^4.9.5" } }, "node_modules/@adobe/css-tools": { @@ -4779,6 +4780,15 @@ "@types/node": "*" } }, + "node_modules/@types/hoist-non-react-statics": { + "version": "3.3.6", + "resolved": "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.6.tgz", + "integrity": "sha512-lPByRJUer/iN/xa4qpyL0qmL11DqNW81iU/IG1S3uvRUq4oKagz8VCxZjiWkumgt66YT3vOdDgZ0o32sGKtCEw==", + "dependencies": { + "@types/react": "*", + "hoist-non-react-statics": "^3.3.0" + } + }, "node_modules/@types/html-minifier-terser": { "version": "6.1.0", "resolved": "https://registry.npmjs.org/@types/html-minifier-terser/-/html-minifier-terser-6.1.0.tgz", @@ -5001,6 +5011,16 @@ "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.3.tgz", "integrity": "sha512-9aEbYZ3TbYMznPdcdr3SmIrLXwC/AKZXQeCf9Pgao5CKb8CyHuEX5jzWPTkvregvhRJHcpRO6BFoGW9ycaOkYw==" }, + "node_modules/@types/styled-components": { + "version": "5.1.34", + "resolved": "https://registry.npmjs.org/@types/styled-components/-/styled-components-5.1.34.tgz", + "integrity": "sha512-mmiVvwpYklFIv9E8qfxuPyIt/OuyIrn6gMOAMOFUO3WJfSrSE+sGUoa4PiZj77Ut7bKZpaa6o1fBKS/4TOEvnA==", + "dependencies": { + "@types/hoist-non-react-statics": "*", + "@types/react": "*", + "csstype": "^3.0.2" + } + }, "node_modules/@types/stylis": { "version": "4.2.5", "resolved": "https://registry.npmjs.org/@types/stylis/-/stylis-4.2.5.tgz", @@ -17904,15 +17924,15 @@ } }, "node_modules/typescript": { - "version": "5.7.3", - "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.7.3.tgz", - "integrity": "sha512-84MVSjMEHP+FQRPy3pX9sTVV/INIex71s9TL2Gm5FG/WG1SqXeKyZ0k7/blY/4FdOzI12CBy1vGc4og/eus0fw==", + "version": "4.9.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", + "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" }, "engines": { - "node": ">=14.17" + "node": ">=4.2.0" } }, "node_modules/unbox-primitive": { diff --git a/package.json b/package.json index 0732f6c6..09c65e00 100644 --- a/package.json +++ b/package.json @@ -6,6 +6,7 @@ "@testing-library/jest-dom": "^5.17.0", "@testing-library/react": "^13.4.0", "@testing-library/user-event": "^13.5.0", + "@types/styled-components": "^5.1.34", "axios": "^1.7.9", "firebase": "^11.1.0", "lodash.throttle": "^4.1.1", @@ -44,6 +45,6 @@ "devDependencies": { "@types/react": "^19.0.10", "@types/react-dom": "^19.0.4", - "typescript": "^5.7.3" + "typescript": "^4.9.5" } } diff --git "a/src/pages/\bItemsPage/ItemsPage.jsx" "b/src/pages/\bItemsPage/ItemsPage.tsx" similarity index 100% rename from "src/pages/\bItemsPage/ItemsPage.jsx" rename to "src/pages/\bItemsPage/ItemsPage.tsx" From 1cb5a0867b09ba8196c851c61df0a1a933a8fce3 Mon Sep 17 00:00:00 2001 From: nerte Date: Thu, 20 Feb 2025 17:00:24 +0900 Subject: [PATCH 11/38] [Types] add declaration file for SVG imports and select componenet type --- .../{Select.style.jsx => Select.style.tsx} | 5 ++- .../common/Select/{Select.jsx => Select.tsx} | 25 +++++++------- .../pages/\bItemsPage/ItemsPage.style.tsx" | 0 "src/pages/\bItemsPage/ItemsPage.tsx" | 33 +++++++++++++------ src/types/declaration.d.ts | 4 +++ tsconfig.json | 2 +- 6 files changed, 44 insertions(+), 25 deletions(-) rename src/components/common/Select/{Select.style.jsx => Select.style.tsx} (95%) rename src/components/common/Select/{Select.jsx => Select.tsx} (75%) rename "src/pages/\bItemsPage/ItemsPage.style.jsx" => "src/pages/\bItemsPage/ItemsPage.style.tsx" (100%) create mode 100644 src/types/declaration.d.ts diff --git a/src/components/common/Select/Select.style.jsx b/src/components/common/Select/Select.style.tsx similarity index 95% rename from src/components/common/Select/Select.style.jsx rename to src/components/common/Select/Select.style.tsx index 42864b4e..a9b6d8f8 100644 --- a/src/components/common/Select/Select.style.jsx +++ b/src/components/common/Select/Select.style.tsx @@ -1,6 +1,9 @@ import styled from "styled-components"; import theme from "../../../style/theme"; +type isOpen = { + $isOpen: boolean; +}; export const DropDown = styled.div` position: relative; `; @@ -19,7 +22,7 @@ export const Selected = styled.div` z-index: 99; `; -export const Options = styled.ul` +export const Options = styled.ul` display: ${({ $isOpen }) => ($isOpen ? "block" : "none")}; background-color: ${theme.color.white}; color: ${theme.color.gray400}; diff --git a/src/components/common/Select/Select.jsx b/src/components/common/Select/Select.tsx similarity index 75% rename from src/components/common/Select/Select.jsx rename to src/components/common/Select/Select.tsx index c205338e..2b56cecb 100644 --- a/src/components/common/Select/Select.jsx +++ b/src/components/common/Select/Select.tsx @@ -7,15 +7,18 @@ import { useAutoClose } from "../../../hooks/useAutoClose"; import { button } from "../../../constants/globalConstant"; import useWindowSize from "../../../hooks/useWindowSize"; // +interface Props { + onChange: (option: string) => void; +} -export function SortSelect({ onChange, ...props }) { +export function SortSelect({ onChange, ...props }: Props) { const device = useWindowSize(); const options = ["최신순", "좋아요순"]; - const [selected, setSelected] = useState("최신순"); - const { ref, isOpen, setIsOpen } = useAutoClose(false); + const [selected, setSelected] = useState("최신순"); + const { ref, isOpen, setIsOpen } = useAutoClose(false); //TODO - const handleOptionClick = (option) => { + const handleOptionClick = (option: string) => { setSelected(option); setIsOpen(false); onChange(option); @@ -25,11 +28,11 @@ export function SortSelect({ onChange, ...props }) { <> {device === "mobile" ? ( - setIsOpen(!isOpen)}> + setIsOpen(!isOpen)}> ) : ( - setIsOpen(!isOpen)}> + setIsOpen(!isOpen)}> {selected} 정렬 @@ -50,11 +53,11 @@ export function SortSelect({ onChange, ...props }) { ); } -export function EditSelect({ onChange, ...props }) { +export function EditSelect({ onChange, ...props }: Props) { const options = [button.edit, button.delete]; const { ref, isOpen, setIsOpen } = useAutoClose(false); - const handleOptionClick = (option) => { + const handleOptionClick = (option: string) => { setIsOpen(false); onChange(option); }; @@ -62,11 +65,7 @@ export function EditSelect({ onChange, ...props }) { return ( <> - setIsOpen(!isOpen)} - {...props} - > + setIsOpen(!isOpen)} {...props}> 케밥 diff --git "a/src/pages/\bItemsPage/ItemsPage.style.jsx" "b/src/pages/\bItemsPage/ItemsPage.style.tsx" similarity index 100% rename from "src/pages/\bItemsPage/ItemsPage.style.jsx" rename to "src/pages/\bItemsPage/ItemsPage.style.tsx" diff --git "a/src/pages/\bItemsPage/ItemsPage.tsx" "b/src/pages/\bItemsPage/ItemsPage.tsx" index 3503c61c..106164a4 100644 --- "a/src/pages/\bItemsPage/ItemsPage.tsx" +++ "b/src/pages/\bItemsPage/ItemsPage.tsx" @@ -8,22 +8,35 @@ import PageCount from "../../components/PageNation/pageCount"; import useWindowSize from "../../hooks/useWindowSize"; import { SortSelect } from "../../components/common/Select/Select"; import Button from "../../components/common/Button/Button"; -import { SearchInput } from "../../components/common/Input/Input"; // - +import { SearchInput } from "../../components/common/Input/Input"; +// +interface Item { + id: number; + name: string; + description: string; + price: number; + tags: string[]; + images: [string]; + ownerId: number; + favoriteCount: number; + createdAt: Date; + updatedAt: Date; +} // +export const INITIAL_ITEM: Item[] = []; function HomePage() { - const [items, setItems] = useState([]); - const [selectedOrder, setSelectedOrder] = useState("최신순"); - const [bestItems, setBestItems] = useState([]); - const [page, setPage] = useState(1); - const device = useWindowSize(); + const [items, setItems] = useState(INITIAL_ITEM); + const [selectedOrder, setSelectedOrder] = useState("최신순"); + const [bestItems, setBestItems] = useState(INITIAL_ITEM); + const [page, setPage] = useState(1); + const device = useWindowSize(); // useWindow 타입 지정해주기 const navigate = useNavigate(); // - const handleChangeSort = (option) => { + const handleChangeSort = (option:string) => { setSelectedOrder(option); }; - const handleLoad = async (options) => { + const handleLoad = async (options:{ selectedOrder: string, device: string,page: number }) => { const { list: bestItems } = await bestProducts(options); const { list } = await getProducts(options); setItems(list); @@ -35,7 +48,7 @@ function HomePage() { }; useEffect(() => { - handleLoad({ selectedOrder, device, page }); + handleLoad({ selectedOrder, device:, page }); }, [selectedOrder, page, device]); return ( diff --git a/src/types/declaration.d.ts b/src/types/declaration.d.ts new file mode 100644 index 00000000..5e52f805 --- /dev/null +++ b/src/types/declaration.d.ts @@ -0,0 +1,4 @@ +declare module "*.svg" { + const content: string; + export default content; +} diff --git a/tsconfig.json b/tsconfig.json index b4023d85..f8019780 100644 --- a/tsconfig.json +++ b/tsconfig.json @@ -13,7 +13,7 @@ /* Language and Environment */ "target": "es2016" /* Set the JavaScript language version for emitted JavaScript and include compatible library declarations. */, // "lib": [], /* Specify a set of bundled library declaration files that describe the target runtime environment. */ - // "jsx": "preserve", /* Specify what JSX code is generated. */ + "jsx": "react-jsx" /* Specify what JSX code is generated. */, // "experimentalDecorators": true, /* Enable experimental support for legacy experimental decorators. */ // "emitDecoratorMetadata": true, /* Emit design-type metadata for decorated declarations in source files. */ // "jsxFactory": "", /* Specify the JSX factory function used when targeting React JSX emit, e.g. 'React.createElement' or 'h'. */ From 167dcc05825a1ad6a417397d21b1c33d7c0e3509 Mon Sep 17 00:00:00 2001 From: nerte Date: Sat, 22 Feb 2025 13:51:13 +0900 Subject: [PATCH 12/38] [Type] button componente type --- src/Main.jsx | 2 +- src/components/CommentCard/CommentCard.jsx | 2 +- src/components/common/Button/Button.jsx | 13 ---------- .../{Button.style.jsx => Button.style.tsx} | 7 ++++-- src/components/common/Button/Button.tsx | 19 +++++++++++++++ "src/pages/\bItemsPage/ItemsPage.tsx" | 24 +++++++++++-------- .../{AddItem.style.jsx => AddItem.style.tsx} | 0 .../AddItem/{AddItem.jsx => AddItem.tsx} | 17 ++++++++++--- src/pages/ProductPage/Comments.jsx | 2 +- ...{Comments.style.jsx => Comments.style.tsx} | 0 .../{Product.style.jsx => Product.style.tsx} | 0 src/pages/ProductPage/ProductInfo.jsx | 2 +- ...ctInfo.style.jsx => ProductInfo.style.tsx} | 0 13 files changed, 56 insertions(+), 32 deletions(-) delete mode 100644 src/components/common/Button/Button.jsx rename src/components/common/Button/{Button.style.jsx => Button.style.tsx} (83%) create mode 100644 src/components/common/Button/Button.tsx rename src/pages/AddItem/{AddItem.style.jsx => AddItem.style.tsx} (100%) rename src/pages/AddItem/{AddItem.jsx => AddItem.tsx} (90%) rename src/pages/ProductPage/{Comments.style.jsx => Comments.style.tsx} (100%) rename src/pages/ProductPage/{Product.style.jsx => Product.style.tsx} (100%) rename src/pages/ProductPage/{ProductInfo.style.jsx => ProductInfo.style.tsx} (100%) diff --git a/src/Main.jsx b/src/Main.jsx index 0d95dd60..9b73ebec 100644 --- a/src/Main.jsx +++ b/src/Main.jsx @@ -3,7 +3,7 @@ import GlobalStyle from "./style/globalStyle.js"; // import LandingPage from "./pages/LandingPage/LandingPage.jsx"; import App from "./App.js"; -import ItemsPage from "./pages/ItemsPage/ItemsPage.jsx"; +import ItemsPage from "./pages/ItemsPage/ItemsPage.tsx"; import AddItem from "./pages/AddItem/AddItem.jsx"; import Product from "./pages/ProductPage/Product.jsx"; import Test from "./components/TestPage.jsx"; diff --git a/src/components/CommentCard/CommentCard.jsx b/src/components/CommentCard/CommentCard.jsx index 486ad262..16b60783 100644 --- a/src/components/CommentCard/CommentCard.jsx +++ b/src/components/CommentCard/CommentCard.jsx @@ -3,7 +3,7 @@ import { useEffect, useState } from "react"; import * as S from "./CommentCard.style.jsx"; import defaultImg from "../../assets/icons/default.profile.icon.svg"; import { Input } from "../common/Input/Input.jsx"; -import { EditSelect } from "../common/Select/Select.jsx"; +import { EditSelect } from "../common/Select/Select.tsx"; import { button } from "../../constants/globalConstant.jsx"; import { useFormatUpDate } from "../../hooks/useFormatting.jsx"; // diff --git a/src/components/common/Button/Button.jsx b/src/components/common/Button/Button.jsx deleted file mode 100644 index 83f58541..00000000 --- a/src/components/common/Button/Button.jsx +++ /dev/null @@ -1,13 +0,0 @@ -import * as S from "./Button.style"; -// -//버튼 컨테이너 필요 -export default function Button({ onClick, children, ...props }) { - const { value, square, ...rest } = props; - return ( - <> - - {children} - - - ); -} diff --git a/src/components/common/Button/Button.style.jsx b/src/components/common/Button/Button.style.tsx similarity index 83% rename from src/components/common/Button/Button.style.jsx rename to src/components/common/Button/Button.style.tsx index 1c1f4dc0..e16d15df 100644 --- a/src/components/common/Button/Button.style.jsx +++ b/src/components/common/Button/Button.style.tsx @@ -1,8 +1,11 @@ import styled, { css } from "styled-components"; import theme from "../../../style/theme"; // - -export const Button = styled.button` +interface ButtonProps { + $medium?: boolean; + $circle?: boolean; +} +export const Button = styled.button` display: flex; justify-content: center; align-items: center; diff --git a/src/components/common/Button/Button.tsx b/src/components/common/Button/Button.tsx new file mode 100644 index 00000000..ee225372 --- /dev/null +++ b/src/components/common/Button/Button.tsx @@ -0,0 +1,19 @@ +import * as S from "./Button.style"; +import { ReactNode, MouseEvent } from "react"; + +// + +interface Props { + onClick: (e: MouseEvent) => void; + children: ReactNode; + disabled?: boolean; +} +export default function Button({ onClick, children, ...props }: Props) { + return ( + <> + + {children} + + + ); +} diff --git "a/src/pages/\bItemsPage/ItemsPage.tsx" "b/src/pages/\bItemsPage/ItemsPage.tsx" index 106164a4..c15c6fd4 100644 --- "a/src/pages/\bItemsPage/ItemsPage.tsx" +++ "b/src/pages/\bItemsPage/ItemsPage.tsx" @@ -2,13 +2,13 @@ import { useEffect, useState } from "react"; import { useNavigate } from "react-router-dom"; // import * as S from "./ItemsPage.style"; -import ItemsList from "../../components/ItemsList/ItemsList"; +import ItemsList from "../../components/ItemsList/ItemsList"; //ToDo import { getProducts, bestProducts } from "../../api/product.api"; -import PageCount from "../../components/PageNation/pageCount"; -import useWindowSize from "../../hooks/useWindowSize"; +import PageCount from "../../components/PageNation/pageCount"; //ToDo +import useWindowSize from "../../hooks/useWindowSize"; //Todo import { SortSelect } from "../../components/common/Select/Select"; import Button from "../../components/common/Button/Button"; -import { SearchInput } from "../../components/common/Input/Input"; +import { SearchInput } from "../../components/common/Input/Input"; //ToDo // interface Item { id: number; @@ -32,23 +32,27 @@ function HomePage() { const device = useWindowSize(); // useWindow 타입 지정해주기 const navigate = useNavigate(); // - const handleChangeSort = (option:string) => { + const handleChangeSort = (option: string) => { setSelectedOrder(option); }; - const handleLoad = async (options:{ selectedOrder: string, device: string,page: number }) => { + const handleLoad = async (options: { + selectedOrder: string; + device: string; + page: number; + }) => { const { list: bestItems } = await bestProducts(options); const { list } = await getProducts(options); setItems(list); setBestItems(bestItems); }; - const handleClickPageChange = (value) => { + const handleClickPageChange = (value: number) => { setPage(Number(value)); }; useEffect(() => { - handleLoad({ selectedOrder, device:, page }); + handleLoad({ selectedOrder, device, page }); }, [selectedOrder, page, device]); return ( @@ -74,7 +78,7 @@ function HomePage() { placeholder="검색할 상품을 입력해주세요" onChange={() => {}} /> - + ) : ( @@ -93,7 +97,7 @@ function HomePage() { - + )} diff --git a/src/pages/AddItem/AddItem.style.jsx b/src/pages/AddItem/AddItem.style.tsx similarity index 100% rename from src/pages/AddItem/AddItem.style.jsx rename to src/pages/AddItem/AddItem.style.tsx diff --git a/src/pages/AddItem/AddItem.jsx b/src/pages/AddItem/AddItem.tsx similarity index 90% rename from src/pages/AddItem/AddItem.jsx rename to src/pages/AddItem/AddItem.tsx index 257f32a9..8e897cdd 100644 --- a/src/pages/AddItem/AddItem.jsx +++ b/src/pages/AddItem/AddItem.tsx @@ -5,7 +5,14 @@ import * as S from "./AddItem.style"; import Tag from "../../components/Tag/Tag"; import { useState } from "react"; // -const INITIAL_DATA = { +interface Form { + img: string; + name: string; + content: string; + price: number; + tags: string[]; +} +const INITIAL_DATA: Form = { img: "", name: "", content: "", @@ -15,7 +22,7 @@ const INITIAL_DATA = { const REQUIRED_INPUT = ["name", "content", "tags", "price"]; // function AddItem() { - const [tag, setTag] = useState(""); + const [tag, setTag] = useState(""); const [formData, setFormData] = useState(INITIAL_DATA); // const handleChange = (e) => { @@ -59,13 +66,17 @@ function AddItem() { return false; } }); + + const handleClickSubmit = () => {}; return ( 상품 등록하기 - + diff --git a/src/pages/ProductPage/Comments.jsx b/src/pages/ProductPage/Comments.jsx index 49b80356..3b0ebe87 100644 --- a/src/pages/ProductPage/Comments.jsx +++ b/src/pages/ProductPage/Comments.jsx @@ -1,7 +1,7 @@ import { useState, useEffect } from "react"; import { useNavigate } from "react-router-dom"; // -import * as S from "./Comments.style"; +import * as S from "./Comments.style.tsx"; import { placeholder } from "../../constants/globalConstant"; import { button } from "../../constants/globalConstant"; import noComment from "../../assets/no-comments.svg"; diff --git a/src/pages/ProductPage/Comments.style.jsx b/src/pages/ProductPage/Comments.style.tsx similarity index 100% rename from src/pages/ProductPage/Comments.style.jsx rename to src/pages/ProductPage/Comments.style.tsx diff --git a/src/pages/ProductPage/Product.style.jsx b/src/pages/ProductPage/Product.style.tsx similarity index 100% rename from src/pages/ProductPage/Product.style.jsx rename to src/pages/ProductPage/Product.style.tsx diff --git a/src/pages/ProductPage/ProductInfo.jsx b/src/pages/ProductPage/ProductInfo.jsx index c92eebd7..61e5e23e 100644 --- a/src/pages/ProductPage/ProductInfo.jsx +++ b/src/pages/ProductPage/ProductInfo.jsx @@ -3,7 +3,7 @@ import { useState, useEffect } from "react"; import profile from "../../assets/icons/default.profile.icon.svg"; // import { getProductInfo } from "../../api/product.api"; -import * as S from "./ProductInfo.style"; +import * as S from "./ProductInfo.style.tsx"; import Tag from "../../components/Tag/Tag"; import BtnHeart from "../../components/common/BtnHeart/BtnHeart"; import { EditSelect } from "../../components/common/Select/Select"; diff --git a/src/pages/ProductPage/ProductInfo.style.jsx b/src/pages/ProductPage/ProductInfo.style.tsx similarity index 100% rename from src/pages/ProductPage/ProductInfo.style.jsx rename to src/pages/ProductPage/ProductInfo.style.tsx From 212edd8d05f57ea4ee14537073632e9890cf358d Mon Sep 17 00:00:00 2001 From: nerte Date: Sat, 22 Feb 2025 16:01:58 +0900 Subject: [PATCH 13/38] [Type] input component type --- .../{Input.style.jsx => Input.style.tsx} | 10 ++++-- .../common/Input/{Input.jsx => Input.tsx} | 35 +++++++++++++------ 2 files changed, 32 insertions(+), 13 deletions(-) rename src/components/common/Input/{Input.style.jsx => Input.style.tsx} (95%) rename src/components/common/Input/{Input.jsx => Input.tsx} (62%) diff --git a/src/components/common/Input/Input.style.jsx b/src/components/common/Input/Input.style.tsx similarity index 95% rename from src/components/common/Input/Input.style.jsx rename to src/components/common/Input/Input.style.tsx index aa8d3b4f..46a925ec 100644 --- a/src/components/common/Input/Input.style.jsx +++ b/src/components/common/Input/Input.style.tsx @@ -1,7 +1,11 @@ import styled, { css } from "styled-components"; import theme from "../../../style/theme"; // - +export interface StyleProps { + $comment: boolean; + $textArea: boolean; + $edit: boolean; +} export const InputWrapper = styled.div` width: 100%; display: flex; @@ -10,7 +14,7 @@ export const InputWrapper = styled.div` gap: 16px; `; -export const Label = styled.label` +export const Label = styled.label` width: 100%; height: 26px; font-size: 18px; @@ -25,7 +29,7 @@ export const Label = styled.label` `} `; -export const Input = styled.input` +export const Input = styled.input` width: 100%; background-color: ${theme.color.gray100}; font-size: 16px; diff --git a/src/components/common/Input/Input.jsx b/src/components/common/Input/Input.tsx similarity index 62% rename from src/components/common/Input/Input.jsx rename to src/components/common/Input/Input.tsx index 0c52278f..b7bf53dc 100644 --- a/src/components/common/Input/Input.jsx +++ b/src/components/common/Input/Input.tsx @@ -2,36 +2,51 @@ import PlusIcon from "../../../assets/icons/plusIcon.svg"; import DeleteIcon from "../../../assets/icons/DeleteIcon.svg"; import SearchIcon from "../../../assets/icons/search.icon.svg"; import * as S from "./Input.style"; -import { useRef, useState } from "react"; + +import { ChangeEvent, useRef, useState } from "react"; // -export function Input({ onChange, ...props }) { + +interface Props extends S.StyleProps { + onChange: (e: ChangeEvent) => void; + label?: string; + placeholder?: string; + name: string; +} +export function Input({ onChange, ...props }: Props) { const { label, ...rest } = props; return ( - {!label && {label}} + {!label && {label}} ); } // -export function ImgInput({ onChange, ...props }) { - const imgRef = useRef(); - const [imgPreview, setImgPreview] = useState(""); +interface ImgProps extends Omit { + onChange: (e: { name: string; value: File | string }) => void; +} + +export function ImgInput({ onChange, ...props }: ImgProps) { + const imgRef = useRef(null); + const [imgPreview, setImgPreview] = useState(""); const handlePreviewImg = () => { + if (!imgRef.current || !imgRef.current.files?.length) return; const file = imgRef.current.files[0]; const reader = new FileReader(); reader.readAsDataURL(file); reader.onloadend = () => { - setImgPreview(reader.result); - onChange({ name: "img", value: file }); //백엔드에서 img를 file 객체안받을시 수정 필요 + if (typeof reader.result === "string") { + setImgPreview(reader.result); + onChange({ name: "img", value: file }); + } }; }; // const handleClickImgDelete = () => { setImgPreview(""); - onChange(""); + onChange({ name: "img", value: " " }); }; return ( @@ -60,7 +75,7 @@ export function ImgInput({ onChange, ...props }) { ); } -export function SearchInput({ onChange, ...props }) { +export function SearchInput({ onChange, ...props }: Props) { return ( From a04e631531d6cce4092fbbd40c74f37eca68974e Mon Sep 17 00:00:00 2001 From: nerte Date: Sat, 22 Feb 2025 16:08:06 +0900 Subject: [PATCH 14/38] [Type] BtnHeart type --- .../{BtnHeart.style.jsx => BtnHeart.style.tsx} | 11 ++++++++--- .../common/BtnHeart/{BtnHeart.jsx => BtnHeart.tsx} | 6 +++++- 2 files changed, 13 insertions(+), 4 deletions(-) rename src/components/common/BtnHeart/{BtnHeart.style.jsx => BtnHeart.style.tsx} (83%) rename src/components/common/BtnHeart/{BtnHeart.jsx => BtnHeart.tsx} (81%) diff --git a/src/components/common/BtnHeart/BtnHeart.style.jsx b/src/components/common/BtnHeart/BtnHeart.style.tsx similarity index 83% rename from src/components/common/BtnHeart/BtnHeart.style.jsx rename to src/components/common/BtnHeart/BtnHeart.style.tsx index ae6032f0..38c10ec0 100644 --- a/src/components/common/BtnHeart/BtnHeart.style.jsx +++ b/src/components/common/BtnHeart/BtnHeart.style.tsx @@ -2,7 +2,12 @@ import styled, { css } from "styled-components"; import theme from "../../../style/theme"; // -export const InactiveBtnHeart = styled.button` +export interface StyledProps { + $small: boolean; + $border: boolean; + $items: boolean; +} +export const InactiveBtnHeart = styled.button` display: flex; align-items: center; justify-content: center; @@ -34,7 +39,7 @@ export const InactiveBtnHeart = styled.button` `}; `; -export const ActiveBtnHeart = styled.button` +export const ActiveBtnHeart = styled.button` display: flex; align-items: center; justify-content: center; @@ -61,7 +66,7 @@ export const ActiveBtnHeart = styled.button` `}; `; -export const HeartImg = styled.img` +export const HeartImg = styled.img` width: 26px; height: 23px; diff --git a/src/components/common/BtnHeart/BtnHeart.jsx b/src/components/common/BtnHeart/BtnHeart.tsx similarity index 81% rename from src/components/common/BtnHeart/BtnHeart.jsx rename to src/components/common/BtnHeart/BtnHeart.tsx index f19fba9e..b925cacf 100644 --- a/src/components/common/BtnHeart/BtnHeart.jsx +++ b/src/components/common/BtnHeart/BtnHeart.tsx @@ -3,7 +3,11 @@ import inactiveHeart from "../../../assets/icons/inactive.heart.icon.svg"; // import * as S from "./BtnHeart.style"; // -export default function BtnHeart({ value, ...props }) { +interface Props extends S.StyledProps { + value: number; + active: boolean; +} +export default function BtnHeart({ value, ...props }: Props) { const { active, ...rest } = props; return ( <> From 3210bd488a84683e1b8d4ee1d6fc28693f20ad62 Mon Sep 17 00:00:00 2001 From: nerte Date: Sun, 23 Feb 2025 11:42:09 +0900 Subject: [PATCH 15/38] [Type] Convert JSX to TSX and add type for AddItem --- src/components/common/Input/Input.style.tsx | 6 +++--- src/components/common/Input/Input.tsx | 16 ++++++++++------ "src/pages/\bItemsPage/ItemsPage.tsx" | 4 +++- src/pages/AddItem/AddItem.tsx | 20 +++++++++++++------- 4 files changed, 29 insertions(+), 17 deletions(-) diff --git a/src/components/common/Input/Input.style.tsx b/src/components/common/Input/Input.style.tsx index 46a925ec..193ca0fe 100644 --- a/src/components/common/Input/Input.style.tsx +++ b/src/components/common/Input/Input.style.tsx @@ -2,9 +2,9 @@ import styled, { css } from "styled-components"; import theme from "../../../style/theme"; // export interface StyleProps { - $comment: boolean; - $textArea: boolean; - $edit: boolean; + $comment?: boolean; + $textArea?: boolean; + $edit?: boolean; } export const InputWrapper = styled.div` width: 100%; diff --git a/src/components/common/Input/Input.tsx b/src/components/common/Input/Input.tsx index b7bf53dc..2d019e94 100644 --- a/src/components/common/Input/Input.tsx +++ b/src/components/common/Input/Input.tsx @@ -11,9 +11,13 @@ interface Props extends S.StyleProps { label?: string; placeholder?: string; name: string; + tag?: boolean; + value?: string; + onKeyUp?: (e: React.KeyboardEvent) => void; + type?: "text" | "number" | "password" | "email"; } -export function Input({ onChange, ...props }: Props) { - const { label, ...rest } = props; +export function Input({ onChange, type = "text", ...props }: Props) { + const { label, onKeyUp, ...rest } = props; return ( @@ -24,9 +28,8 @@ export function Input({ onChange, ...props }: Props) { } // interface ImgProps extends Omit { - onChange: (e: { name: string; value: File | string }) => void; + onChange: (value: File | string) => void; } - export function ImgInput({ onChange, ...props }: ImgProps) { const imgRef = useRef(null); const [imgPreview, setImgPreview] = useState(""); @@ -39,14 +42,14 @@ export function ImgInput({ onChange, ...props }: ImgProps) { reader.onloadend = () => { if (typeof reader.result === "string") { setImgPreview(reader.result); - onChange({ name: "img", value: file }); + onChange(file); } }; }; // const handleClickImgDelete = () => { setImgPreview(""); - onChange({ name: "img", value: " " }); + onChange(""); }; return ( @@ -75,6 +78,7 @@ export function ImgInput({ onChange, ...props }: ImgProps) { ); } + export function SearchInput({ onChange, ...props }: Props) { return ( diff --git "a/src/pages/\bItemsPage/ItemsPage.tsx" "b/src/pages/\bItemsPage/ItemsPage.tsx" index c15c6fd4..19aa93b2 100644 --- "a/src/pages/\bItemsPage/ItemsPage.tsx" +++ "b/src/pages/\bItemsPage/ItemsPage.tsx" @@ -8,7 +8,7 @@ import PageCount from "../../components/PageNation/pageCount"; //ToDo import useWindowSize from "../../hooks/useWindowSize"; //Todo import { SortSelect } from "../../components/common/Select/Select"; import Button from "../../components/common/Button/Button"; -import { SearchInput } from "../../components/common/Input/Input"; //ToDo +import { SearchInput } from "../../components/common/Input/Input"; // interface Item { id: number; @@ -75,6 +75,7 @@ function HomePage() { {}} /> @@ -87,6 +88,7 @@ function HomePage() { {}} /> diff --git a/src/pages/AddItem/AddItem.tsx b/src/pages/AddItem/AddItem.tsx index 8e897cdd..379ac521 100644 --- a/src/pages/AddItem/AddItem.tsx +++ b/src/pages/AddItem/AddItem.tsx @@ -3,14 +3,16 @@ import { placeholder, button } from "../../constants/globalConstant"; import * as I from "../../components/common/Input/Input"; import * as S from "./AddItem.style"; import Tag from "../../components/Tag/Tag"; -import { useState } from "react"; +import { ChangeEvent, useState } from "react"; + // interface Form { - img: string; + img: string | File; name: string; content: string; price: number; tags: string[]; + [key: string]: string | File | number | string[]; } const INITIAL_DATA: Form = { img: "", @@ -25,12 +27,16 @@ function AddItem() { const [tag, setTag] = useState(""); const [formData, setFormData] = useState(INITIAL_DATA); // - const handleChange = (e) => { + const handleChange = (e: ChangeEvent) => { setFormData({ ...formData, [e.target.name]: e.target.value }); //ToDo: img 프로퍼티에는 imgInput에서 넘겨준 file 객체가 담기고 있음 }; - const CreateTag = (e) => { + const handleImgChange = (value: File | string) => { + setFormData({ ...formData, img: value }); + }; + + const CreateTag = (e: React.KeyboardEvent) => { if (e.key === "Enter" && tag.trim() !== "") { const notDuplicate = formData.tags.includes(tag.trim()); if (!notDuplicate) { @@ -40,11 +46,11 @@ function AddItem() { })); } setTag(""); - e.target.value = ""; + (e.target as HTMLInputElement).value = ""; } }; - const handleClickTagDelete = (tag) => { + const handleClickTagDelete = (tag: string) => { const filterTags = formData.tags.filter((prev) => prev !== tag); setFormData((prev) => ({ ...prev, tags: filterTags })); }; @@ -83,7 +89,7 @@ function AddItem() { Date: Sun, 23 Feb 2025 11:59:56 +0900 Subject: [PATCH 16/38] [Type]Convert JSX to TSX and add type for Tag --- .../Tag/{Tag.style.jsx => Tag.style.tsx} | 11 +++++++++-- src/components/Tag/{Tag.jsx => Tag.tsx} | 18 ++++++++---------- 2 files changed, 17 insertions(+), 12 deletions(-) rename src/components/Tag/{Tag.style.jsx => Tag.style.tsx} (76%) rename src/components/Tag/{Tag.jsx => Tag.tsx} (52%) diff --git a/src/components/Tag/Tag.style.jsx b/src/components/Tag/Tag.style.tsx similarity index 76% rename from src/components/Tag/Tag.style.jsx rename to src/components/Tag/Tag.style.tsx index 2c24e7bf..03865ea0 100644 --- a/src/components/Tag/Tag.style.jsx +++ b/src/components/Tag/Tag.style.tsx @@ -1,7 +1,14 @@ import styled, { css } from "styled-components"; import theme from "../../style/theme"; -export const TagsContainer = styled.div` +export interface StyledProps { + $product?: boolean; +} +interface DeleteButtonProps { + tag: string; + onClick?: () => void; +} +export const TagsContainer = styled.div` width: 100%; display: flex; gap: 12px; @@ -38,7 +45,7 @@ export const Tag = styled.div` @media (min-width: 376px) and (max-width: 768px) { } `; -export const DeleteButton = styled.img` +export const DeleteButton = styled.img` width: 22px; height: 22px; `; diff --git a/src/components/Tag/Tag.jsx b/src/components/Tag/Tag.tsx similarity index 52% rename from src/components/Tag/Tag.jsx rename to src/components/Tag/Tag.tsx index f84891cf..ad4c7353 100644 --- a/src/components/Tag/Tag.jsx +++ b/src/components/Tag/Tag.tsx @@ -1,22 +1,20 @@ import DeleteButton from "../../assets/icons/DeleteIcon.svg"; import * as S from "./Tag.style"; -export default function Tag({ tags, ...props }) { - const { onClick, ...rest } = props; - //...rest : $product(gap8px,items/id페이지) +// +interface Props extends S.StyledProps { + tags: string[]; +} +export default function Tag({ tags, ...props }: Props) { return ( - + {tags?.length > 0 && tags.map((tag) => { return ( #{tag} - {!rest.$product && ( - onClick(tag)} - src={DeleteButton} - /> + {!props.$product && ( + )} From 8f838caffde213380e22df606c4cfcdc1852330b Mon Sep 17 00:00:00 2001 From: nerte Date: Sun, 23 Feb 2025 14:07:11 +0900 Subject: [PATCH 17/38] [Type] edit type AddItem and Tag --- src/components/Tag/Tag.tsx | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/src/components/Tag/Tag.tsx b/src/components/Tag/Tag.tsx index ad4c7353..5bc9a9da 100644 --- a/src/components/Tag/Tag.tsx +++ b/src/components/Tag/Tag.tsx @@ -3,10 +3,12 @@ import * as S from "./Tag.style"; // interface Props extends S.StyledProps { tags: string[]; + onClick?: (tag: string) => void; } export default function Tag({ tags, ...props }: Props) { + const { onClick, ...rest } = props; return ( - + {tags?.length > 0 && tags.map((tag) => { return ( @@ -14,7 +16,7 @@ export default function Tag({ tags, ...props }: Props) { #{tag} {!props.$product && ( - + )} From b96023446941f1fa96a6fb63eec5f5b0c19d0d6e Mon Sep 17 00:00:00 2001 From: nerte Date: Sun, 23 Feb 2025 14:09:57 +0900 Subject: [PATCH 18/38] [Type]Convert JSX to TSX ItemsList and ItemsList.style and edit type for BtnHeart --- .../ItemsList/{ItemsList.style.jsx => ItemsList.style.tsx} | 0 src/components/ItemsList/{ItemsList.jsx => ItemsList.tsx} | 0 src/components/common/BtnHeart/BtnHeart.style.tsx | 6 +++--- src/components/common/BtnHeart/BtnHeart.tsx | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) rename src/components/ItemsList/{ItemsList.style.jsx => ItemsList.style.tsx} (100%) rename src/components/ItemsList/{ItemsList.jsx => ItemsList.tsx} (100%) diff --git a/src/components/ItemsList/ItemsList.style.jsx b/src/components/ItemsList/ItemsList.style.tsx similarity index 100% rename from src/components/ItemsList/ItemsList.style.jsx rename to src/components/ItemsList/ItemsList.style.tsx diff --git a/src/components/ItemsList/ItemsList.jsx b/src/components/ItemsList/ItemsList.tsx similarity index 100% rename from src/components/ItemsList/ItemsList.jsx rename to src/components/ItemsList/ItemsList.tsx diff --git a/src/components/common/BtnHeart/BtnHeart.style.tsx b/src/components/common/BtnHeart/BtnHeart.style.tsx index 38c10ec0..b6a30a39 100644 --- a/src/components/common/BtnHeart/BtnHeart.style.tsx +++ b/src/components/common/BtnHeart/BtnHeart.style.tsx @@ -3,9 +3,9 @@ import theme from "../../../style/theme"; // export interface StyledProps { - $small: boolean; - $border: boolean; - $items: boolean; + $small?: boolean; + $border?: boolean; + $items?: boolean; } export const InactiveBtnHeart = styled.button` display: flex; diff --git a/src/components/common/BtnHeart/BtnHeart.tsx b/src/components/common/BtnHeart/BtnHeart.tsx index b925cacf..7ce2182a 100644 --- a/src/components/common/BtnHeart/BtnHeart.tsx +++ b/src/components/common/BtnHeart/BtnHeart.tsx @@ -5,7 +5,7 @@ import * as S from "./BtnHeart.style"; // interface Props extends S.StyledProps { value: number; - active: boolean; + active?: boolean; } export default function BtnHeart({ value, ...props }: Props) { const { active, ...rest } = props; From 7bb8e2423e1f7dfe8740c77164aa1d593f6d5b28 Mon Sep 17 00:00:00 2001 From: nerte Date: Sun, 23 Feb 2025 14:55:53 +0900 Subject: [PATCH 19/38] [Type] add type for ItemsPage and ItemsPage.style --- src/components/ItemsList/ItemsList.style.tsx | 29 +++++++++++++++++--- src/components/ItemsList/ItemsList.tsx | 28 ++++++++++++------- "src/pages/\bItemsPage/ItemsPage.tsx" | 4 +-- 3 files changed, 45 insertions(+), 16 deletions(-) diff --git a/src/components/ItemsList/ItemsList.style.tsx b/src/components/ItemsList/ItemsList.style.tsx index 8c18563a..af665f9f 100644 --- a/src/components/ItemsList/ItemsList.style.tsx +++ b/src/components/ItemsList/ItemsList.style.tsx @@ -1,6 +1,27 @@ import styled from "styled-components"; import theme from "../../style/theme"; -const ByDevice = { + +interface Props { + value: string; + $device: string; +} + +interface Device { + gap: string; + gridTemplate: string; + gridRow: string; + height: string; +} + +interface DeviceStyle { + [key: string]: { + mobile: Device; + tablet: Device; + desktop: Device; + [key: string]: Device; + }; +} +const ByDevice: DeviceStyle = { best: { mobile: { gap: "none", @@ -31,8 +52,8 @@ const ByDevice = { tablet: { gap: "40px 24px", gridTemplate: "repeat(3, 221px)", - height: "221px", gridRow: "317px", + height: "221px", }, desktop: { gap: "40px 24px", @@ -48,7 +69,7 @@ export const Item = styled.div` flex-direction: column; gap: 16px; `; -export const ProductImg = styled.img` +export const ProductImg = styled.img` aspect-ratio: 1/1; height: ${({ $device, value }) => ByDevice[value][$device].height || "auto"}; border-radius: 16px; @@ -70,7 +91,7 @@ export const Price = styled.div` color: ${theme.color.gray800}; `; -export const ItemListStyle = styled.div` +export const ItemListStyle = styled.div` margin: 24px auto; display: grid; gap: ${({ $device, value }) => ByDevice[value][$device].gap}; diff --git a/src/components/ItemsList/ItemsList.tsx b/src/components/ItemsList/ItemsList.tsx index f1cf61b5..3f94782d 100644 --- a/src/components/ItemsList/ItemsList.tsx +++ b/src/components/ItemsList/ItemsList.tsx @@ -3,36 +3,44 @@ import useWindowSize from "../../hooks/useWindowSize"; // import * as S from "./ItemsList.style"; import BtnHeart from "../common/BtnHeart/BtnHeart"; +import { Item } from "../../pages/ItemsPage/ItemsPage"; // -function ListItem({ value, items }) { + +interface Prop { + value: string; + items: Item[]; +} +interface ListItemProps { + value: string; + item: Item; +} +function ListItem({ value, item }: ListItemProps) { const navigate = useNavigate(); const device = useWindowSize(); return ( - navigate(`./${items.id}`)}> + navigate(`./${item.id}`)}> - {items.name} - {items.price} 원 - + {item.name} + {item.price} 원 + ); } // -export default function ItemsList({ value, items, ...props }) { +export default function ItemsList({ value, items, ...props }: Prop) { const device = useWindowSize(); return ( {items.map((item) => { - return ( - - ); + return ; })} ); diff --git "a/src/pages/\bItemsPage/ItemsPage.tsx" "b/src/pages/\bItemsPage/ItemsPage.tsx" index 19aa93b2..17528919 100644 --- "a/src/pages/\bItemsPage/ItemsPage.tsx" +++ "b/src/pages/\bItemsPage/ItemsPage.tsx" @@ -2,7 +2,7 @@ import { useEffect, useState } from "react"; import { useNavigate } from "react-router-dom"; // import * as S from "./ItemsPage.style"; -import ItemsList from "../../components/ItemsList/ItemsList"; //ToDo +import ItemsList from "../../components/ItemsList/ItemsList"; import { getProducts, bestProducts } from "../../api/product.api"; import PageCount from "../../components/PageNation/pageCount"; //ToDo import useWindowSize from "../../hooks/useWindowSize"; //Todo @@ -10,7 +10,7 @@ import { SortSelect } from "../../components/common/Select/Select"; import Button from "../../components/common/Button/Button"; import { SearchInput } from "../../components/common/Input/Input"; // -interface Item { +export interface Item { id: number; name: string; description: string; From 3f77bf3b18fe9a3fe88de40971e42ef15524a9ef Mon Sep 17 00:00:00 2001 From: nerte Date: Sun, 23 Feb 2025 18:42:28 +0900 Subject: [PATCH 20/38] [Type]Convert JSX to TSX CommentCard , Comment, Product --- src/api/comment.api.jsx | 2 +- ...ntCard.style.jsx => CommentCard.style.tsx} | 0 .../{CommentCard.jsx => CommentCard.tsx} | 9 ++--- .../{Comments.jsx => Comments.tsx} | 36 +++++++++++++------ .../ProductPage/{Product.jsx => Product.tsx} | 13 ++++--- 5 files changed, 40 insertions(+), 20 deletions(-) rename src/components/CommentCard/{CommentCard.style.jsx => CommentCard.style.tsx} (100%) rename src/components/CommentCard/{CommentCard.jsx => CommentCard.tsx} (88%) rename src/pages/ProductPage/{Comments.jsx => Comments.tsx} (66%) rename src/pages/ProductPage/{Product.jsx => Product.tsx} (59%) diff --git a/src/api/comment.api.jsx b/src/api/comment.api.jsx index 2c861071..0e14ef63 100644 --- a/src/api/comment.api.jsx +++ b/src/api/comment.api.jsx @@ -9,7 +9,7 @@ export async function getProductComments(productId, limit = 3) { if (!res) { throw new Error("리뷰 불러오기 실패"); } - return res.data; + return res.data.list; } catch (error) { console.error(error); return null; diff --git a/src/components/CommentCard/CommentCard.style.jsx b/src/components/CommentCard/CommentCard.style.tsx similarity index 100% rename from src/components/CommentCard/CommentCard.style.jsx rename to src/components/CommentCard/CommentCard.style.tsx diff --git a/src/components/CommentCard/CommentCard.jsx b/src/components/CommentCard/CommentCard.tsx similarity index 88% rename from src/components/CommentCard/CommentCard.jsx rename to src/components/CommentCard/CommentCard.tsx index 16b60783..e2835fdc 100644 --- a/src/components/CommentCard/CommentCard.jsx +++ b/src/components/CommentCard/CommentCard.tsx @@ -1,13 +1,14 @@ import { useEffect, useState } from "react"; // -import * as S from "./CommentCard.style.jsx"; +import * as S from "./CommentCard.style.js"; import defaultImg from "../../assets/icons/default.profile.icon.svg"; -import { Input } from "../common/Input/Input.jsx"; -import { EditSelect } from "../common/Select/Select.tsx"; +import { Input } from "../common/Input/Input.js"; +import { EditSelect } from "../common/Select/Select.js"; import { button } from "../../constants/globalConstant.jsx"; import { useFormatUpDate } from "../../hooks/useFormatting.jsx"; +import { Comment } from "../../pages/ProductPage/Comments.js"; // -export default function CommentCard({ data }) { +export default function CommentCard({ data }: Comment) { const [initialValue, setInitialValue] = useState(data.content); const [isEditing, setIsEditing] = useState(null); const [isDelete, setIsDelete] = useState(null); diff --git a/src/pages/ProductPage/Comments.jsx b/src/pages/ProductPage/Comments.tsx similarity index 66% rename from src/pages/ProductPage/Comments.jsx rename to src/pages/ProductPage/Comments.tsx index 3b0ebe87..8bd1e5d6 100644 --- a/src/pages/ProductPage/Comments.jsx +++ b/src/pages/ProductPage/Comments.tsx @@ -1,22 +1,36 @@ import { useState, useEffect } from "react"; import { useNavigate } from "react-router-dom"; // -import * as S from "./Comments.style.tsx"; -import { placeholder } from "../../constants/globalConstant"; -import { button } from "../../constants/globalConstant"; +import * as S from "./Comments.style.js"; +import { placeholder } from "../../constants/globalConstant.jsx"; +import { button } from "../../constants/globalConstant.jsx"; import noComment from "../../assets/no-comments.svg"; import returnIcon from "../../assets/icons/return.icon.svg"; // -import { getProductComments } from "../../api/comment.api"; -import { Input } from "../../components/common/Input/Input"; -import Button from "../../components/common/Button/Button"; -import CommentCard from "../../components/CommentCard/CommentCard"; +import { getProductComments } from "../../api/comment.api.jsx"; +import { Input } from "../../components/common/Input/Input.js"; +import Button from "../../components/common/Button/Button.js"; +import CommentCard from "../../components/CommentCard/CommentCard.jsx"; // -export default function Comments({ productId }) { +interface Writer { + image: string; + nickname: string; + id: number; +} + +export interface Comment { + writer: Writer; + updatedAt: string; // 날짜를 string으로 처리 + createdAt: string; // 날짜를 string으로 처리 + content: string; + id: number; +} + +export default function Comments({ productId }: string) { const [isDisabled, setIsDisabled] = useState(true); - const [comments, setComments] = useState({}); - const [formData, setFormData] = useState(""); + const [comments, setComments] = useState([]); + // const [formData, setFormData] = useState(""); const navigate = useNavigate(); const handleLoad = async () => { const data = await getProductComments(productId); @@ -44,7 +58,7 @@ export default function Comments({ productId }) { - {comments?.list?.length === 0 ? ( + {comments?.length === 0 ? ( diff --git a/src/pages/ProductPage/Product.jsx b/src/pages/ProductPage/Product.tsx similarity index 59% rename from src/pages/ProductPage/Product.jsx rename to src/pages/ProductPage/Product.tsx index a13ff4ab..5168da12 100644 --- a/src/pages/ProductPage/Product.jsx +++ b/src/pages/ProductPage/Product.tsx @@ -5,16 +5,21 @@ import ProductInfo from "./ProductInfo"; import Comments from "./Comments"; import * as S from "./Product.style"; // +interface Params { + productId: string; +} export default function Product() { - const { productId } = useParams(); - + const { productId } = useParams(); + if (!productId) { + alert("페이지를 찾을 수 없습니다. 다시 시도해 주세요"); + } return ( <> - - + + From ef38e4ea2ad5d08ce856799d30fedae52cd5825b Mon Sep 17 00:00:00 2001 From: nerte Date: Sun, 23 Feb 2025 18:56:51 +0900 Subject: [PATCH 21/38] [Type] add type for Comments --- src/components/CommentCard/CommentCard.tsx | 5 ++++- src/components/common/Button/Button.style.tsx | 2 +- src/components/common/Button/Button.tsx | 2 +- src/pages/ProductPage/Comments.tsx | 12 +++++++----- 4 files changed, 13 insertions(+), 8 deletions(-) diff --git a/src/components/CommentCard/CommentCard.tsx b/src/components/CommentCard/CommentCard.tsx index e2835fdc..7a00a858 100644 --- a/src/components/CommentCard/CommentCard.tsx +++ b/src/components/CommentCard/CommentCard.tsx @@ -8,7 +8,10 @@ import { button } from "../../constants/globalConstant.jsx"; import { useFormatUpDate } from "../../hooks/useFormatting.jsx"; import { Comment } from "../../pages/ProductPage/Comments.js"; // -export default function CommentCard({ data }: Comment) { +interface Props { + data: Comment; +} +export default function CommentCard({ data }: Props) { const [initialValue, setInitialValue] = useState(data.content); const [isEditing, setIsEditing] = useState(null); const [isDelete, setIsDelete] = useState(null); diff --git a/src/components/common/Button/Button.style.tsx b/src/components/common/Button/Button.style.tsx index e16d15df..168fac81 100644 --- a/src/components/common/Button/Button.style.tsx +++ b/src/components/common/Button/Button.style.tsx @@ -1,7 +1,7 @@ import styled, { css } from "styled-components"; import theme from "../../../style/theme"; // -interface ButtonProps { +export interface ButtonProps { $medium?: boolean; $circle?: boolean; } diff --git a/src/components/common/Button/Button.tsx b/src/components/common/Button/Button.tsx index ee225372..0773bf2c 100644 --- a/src/components/common/Button/Button.tsx +++ b/src/components/common/Button/Button.tsx @@ -3,7 +3,7 @@ import { ReactNode, MouseEvent } from "react"; // -interface Props { +interface Props extends S.ButtonProps { onClick: (e: MouseEvent) => void; children: ReactNode; disabled?: boolean; diff --git a/src/pages/ProductPage/Comments.tsx b/src/pages/ProductPage/Comments.tsx index 8bd1e5d6..a90afe31 100644 --- a/src/pages/ProductPage/Comments.tsx +++ b/src/pages/ProductPage/Comments.tsx @@ -11,6 +11,7 @@ import { getProductComments } from "../../api/comment.api.jsx"; import { Input } from "../../components/common/Input/Input.js"; import Button from "../../components/common/Button/Button.js"; import CommentCard from "../../components/CommentCard/CommentCard.jsx"; +import { Params } from "./Product.js"; // interface Writer { @@ -21,13 +22,13 @@ interface Writer { export interface Comment { writer: Writer; - updatedAt: string; // 날짜를 string으로 처리 - createdAt: string; // 날짜를 string으로 처리 + updatedAt: string; + createdAt: string; content: string; id: number; } -export default function Comments({ productId }: string) { +export default function Comments({ productId }: Params) { const [isDisabled, setIsDisabled] = useState(true); const [comments, setComments] = useState([]); // const [formData, setFormData] = useState(""); @@ -47,6 +48,7 @@ export default function Comments({ productId }: string) { ) : ( - {comments?.list?.map((data) => ( + {comments?.map((data) => ( ))} )} - From a1639f6e66ab6bec7dc3cfecffb89a9f0e9aca23 Mon Sep 17 00:00:00 2001 From: nerte Date: Sun, 23 Feb 2025 19:02:41 +0900 Subject: [PATCH 22/38] [Type] add type for Product --- src/components/CommentCard/CommentCard.tsx | 1 + src/pages/ProductPage/Product.tsx | 17 ++++++++++------- 2 files changed, 11 insertions(+), 7 deletions(-) diff --git a/src/components/CommentCard/CommentCard.tsx b/src/components/CommentCard/CommentCard.tsx index 7a00a858..c3986aae 100644 --- a/src/components/CommentCard/CommentCard.tsx +++ b/src/components/CommentCard/CommentCard.tsx @@ -36,6 +36,7 @@ export default function CommentCard({ data }: Props) { {data.id === isEditing ? ( setInitialValue(target.value)} diff --git a/src/pages/ProductPage/Product.tsx b/src/pages/ProductPage/Product.tsx index 5168da12..0948b07a 100644 --- a/src/pages/ProductPage/Product.tsx +++ b/src/pages/ProductPage/Product.tsx @@ -1,25 +1,28 @@ -import { useEffect, useState } from "react"; -import { useParams } from "react-router-dom"; +import { useNavigate, useParams } from "react-router-dom"; // import ProductInfo from "./ProductInfo"; import Comments from "./Comments"; import * as S from "./Product.style"; // -interface Params { +export interface Params { productId: string; } export default function Product() { - const { productId } = useParams(); + const navigate = useNavigate(); + const { productId } = useParams>(); + if (!productId) { - alert("페이지를 찾을 수 없습니다. 다시 시도해 주세요"); + navigate("/items"); + alert("해당 상품을 찾을 수 없습니다."); + return; } return ( <> - - + + From 3731caa306792adb3251b30d24902feb376f0261 Mon Sep 17 00:00:00 2001 From: nerte Date: Sun, 23 Feb 2025 19:10:36 +0900 Subject: [PATCH 23/38] [Type] add type for CommentCard --- src/components/CommentCard/CommentCard.tsx | 24 +++++++++++----------- 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/src/components/CommentCard/CommentCard.tsx b/src/components/CommentCard/CommentCard.tsx index c3986aae..b8854f64 100644 --- a/src/components/CommentCard/CommentCard.tsx +++ b/src/components/CommentCard/CommentCard.tsx @@ -13,33 +13,33 @@ interface Props { } export default function CommentCard({ data }: Props) { const [initialValue, setInitialValue] = useState(data.content); - const [isEditing, setIsEditing] = useState(null); - const [isDelete, setIsDelete] = useState(null); + const [EditingId, setEditingId] = useState(0); + const [DeleteId, setDeleteId] = useState(0); const formattedUpdate = useFormatUpDate(data.updatedAt); // - const handleOnChange = (option) => { + const handleOnChange = (option: string) => { if (option === button.edit) { - setIsEditing(data.id); + setEditingId(data.id); } if (option === button.delete) { - setIsDelete(data.id); + setDeleteId(data.id); } return; }; useEffect(() => { //삭제 리퀘스트 예정 - }, [isDelete]); + }, [DeleteId]); // return ( - {data.id === isEditing ? ( + {data.id === EditingId ? ( setInitialValue(target.value)} + onChange={(e) => setInitialValue(e.target.value)} /> ) : ( {initialValue} @@ -58,19 +58,19 @@ export default function CommentCard({ data }: Props) { {formattedUpdate} - {data.id === isEditing && ( + {data.id === EditingId && (
    - setIsEditing("")}> + setEditingId(0)}> {button.cancel} - setIsEditing("")}> + setEditingId(0)}> {button.editConfirm}
    )}
    - {data.id !== isEditing && } + {data.id !== EditingId && }
    ); } From 5fdcc0e80f07c68f9b9e84d82eae0938f9465ced Mon Sep 17 00:00:00 2001 From: nerte Date: Mon, 24 Feb 2025 15:29:58 +0900 Subject: [PATCH 24/38] [Type]Convert JSX to TSX ProductInfo --- src/api/{product.api.jsx => product.api.tsx} | 21 +++++++++--- src/pages/ProductPage/ProductInfo.style.tsx | 5 ++- .../{ProductInfo.jsx => ProductInfo.tsx} | 34 ++++++++++++------- 3 files changed, 43 insertions(+), 17 deletions(-) rename src/api/{product.api.jsx => product.api.tsx} (74%) rename src/pages/ProductPage/{ProductInfo.jsx => ProductInfo.tsx} (65%) diff --git a/src/api/product.api.jsx b/src/api/product.api.tsx similarity index 74% rename from src/api/product.api.jsx rename to src/api/product.api.tsx index 0fc94123..77e00f6e 100644 --- a/src/api/product.api.jsx +++ b/src/api/product.api.tsx @@ -18,7 +18,7 @@ export async function getProducts({ return body; } -export async function bestProducts({ device }) { +export async function bestProducts(device: string) { const pageSize = device === "mobile" ? 1 : device === "tablet" ? 2 : 4; const response = await fetch( `${BASE_URL}/products?orderBy=favorite&pageSize=${pageSize}` @@ -30,13 +30,26 @@ export async function bestProducts({ device }) { return body; } -export async function getProductInfo(productId) { +interface ProductInfo { + createdAt: string; + favoriteCount: number; + ownerNickname: string; + ownerId: Number; + images: [string]; + tags: string[]; + price: number; + description: string; + name: String; + id: number; + isFavorite: Boolean; +} +export async function getProductInfo(productId: string) { try { const response = await axios.get(`${BASE_URL}/products/${productId}`); if (!response) throw new Error("제품정보 get api 실패"); - return response.data; + const data: ProductInfo = response.data; + return data; } catch (error) { console.error(error, "제품정보 api 실패"); - return null; } } diff --git a/src/pages/ProductPage/ProductInfo.style.tsx b/src/pages/ProductPage/ProductInfo.style.tsx index 671e6105..5d252c4c 100644 --- a/src/pages/ProductPage/ProductInfo.style.tsx +++ b/src/pages/ProductPage/ProductInfo.style.tsx @@ -1,6 +1,9 @@ import styled from "styled-components"; import theme from "../../style/theme"; // +export interface Props { + src: string; +} export const ProductInfoWrapper = styled.div` display: flex; gap: 24px; @@ -22,7 +25,7 @@ export const ProductInfoWrapper = styled.div` } `; -export const ProductImg = styled.img` +export const ProductImg = styled.img` width: 100%; height: 100%; border-radius: 16px; diff --git a/src/pages/ProductPage/ProductInfo.jsx b/src/pages/ProductPage/ProductInfo.tsx similarity index 65% rename from src/pages/ProductPage/ProductInfo.jsx rename to src/pages/ProductPage/ProductInfo.tsx index 61e5e23e..b7aa7b3b 100644 --- a/src/pages/ProductPage/ProductInfo.jsx +++ b/src/pages/ProductPage/ProductInfo.tsx @@ -2,18 +2,24 @@ import { useState, useEffect } from "react"; // import profile from "../../assets/icons/default.profile.icon.svg"; // -import { getProductInfo } from "../../api/product.api"; -import * as S from "./ProductInfo.style.tsx"; +import { getProductInfo, ProductInfo } from "../../api/product.api"; +import * as S from "./ProductInfo.style"; import Tag from "../../components/Tag/Tag"; import BtnHeart from "../../components/common/BtnHeart/BtnHeart"; import { EditSelect } from "../../components/common/Select/Select"; import { useFormatDate, useFormatPrice } from "../../hooks/useFormatting"; +import { Params } from "./Product"; // -export default function ProductInfo({ productId }) { - const [product, setProduct] = useState({}); - const formattedDate = useFormatDate(product.createdAt); - const formattedPrice = useFormatPrice(product.price, "KRW"); +export default function ProductInfo({ productId }: Params) { + const [product, setProduct] = useState(); + const formattedDate = product + ? useFormatDate(product.createdAt) + : "날짜 없음"; + const formattedPrice = product + ? useFormatPrice(product.price, "KRW") + : "가격 없음"; + // const handleLoad = async () => { const info = await getProductInfo(productId); @@ -28,7 +34,7 @@ export default function ProductInfo({ productId }) { {product?.images && product?.images?.length > 0 ? ( - + ) : ( 이미지가 없습니다. @@ -37,7 +43,9 @@ export default function ProductInfo({ productId }) { - {product.name} + + {product?.name ?? "상품 이름 없음"} + {formattedPrice}원 @@ -45,11 +53,13 @@ export default function ProductInfo({ productId }) {
    상품소개 - {product.description} + + {product?.description ?? "상품 설명 없음"} + 상품 태그 - +
    @@ -57,12 +67,12 @@ export default function ProductInfo({ productId }) {
    - {product.ownerNickname} + {product?.ownerNickname ?? "닉네임"} {formattedDate}
    - + From 0c34f8499c227188a94b351784c385ad6cd9f20c Mon Sep 17 00:00:00 2001 From: nerte Date: Mon, 24 Feb 2025 15:30:50 +0900 Subject: [PATCH 25/38] [Chore] global.d.ts created --- src/api/product.api.tsx | 2 +- src/types/global.d.ts | 56 +++++++++++++++++++++++++++++++++++++++++ 2 files changed, 57 insertions(+), 1 deletion(-) create mode 100644 src/types/global.d.ts diff --git a/src/api/product.api.tsx b/src/api/product.api.tsx index 77e00f6e..30955c2a 100644 --- a/src/api/product.api.tsx +++ b/src/api/product.api.tsx @@ -30,7 +30,7 @@ export async function bestProducts(device: string) { return body; } -interface ProductInfo { +export interface ProductInfo { createdAt: string; favoriteCount: number; ownerNickname: string; diff --git a/src/types/global.d.ts b/src/types/global.d.ts new file mode 100644 index 00000000..1453b24c --- /dev/null +++ b/src/types/global.d.ts @@ -0,0 +1,56 @@ +export {}; + +//전역 타입을 할 예정 +declare global { + type Product = { + id: number; + name: string; + price: number; + }; + + interface Window { + myGlobalVar: string; + } +} + +//addItem +interface Form { + img: string | File; + name: string; + content: string; + price: number; + tags: string[]; + [key: string]: string | File | number | string[]; +} + +//itemsPage +export interface Item { + id: number; + name: string; + description: string; + price: number; + tags: string[]; + images: [string]; + ownerId: number; + favoriteCount: number; + createdAt: Date; + updatedAt: Date; +} +//comment +interface Writer { + image: string; + nickname: string; + id: number; +} + +export interface Comment { + writer: Writer; + updatedAt: string; + createdAt: string; + content: string; + id: number; +} +//product +export interface Params { + productId: string; +} From a8fd50dd72f217f8adf51ac27fb0fd41726eb10e Mon Sep 17 00:00:00 2001 From: nerte Date: Mon, 24 Feb 2025 15:46:42 +0900 Subject: [PATCH 26/38] =?UTF-8?q?[Type]=20global.d.ts=EC=97=90=20=ED=83=80?= =?UTF-8?q?=EC=9E=85=EC=9D=B4=EB=9E=91=20interface=20=EC=8B=B9=EB=8B=A4=20?= =?UTF-8?q?=EB=AA=A8=EC=9D=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ...ageCount.style.jsx => pageCount.style.tsx} | 6 +- .../{pageCount.jsx => pageCount.tsx} | 18 +-- src/components/TestPage.jsx | 19 --- .../profile.favorite.jsx | 0 .../profile.favorite.style.jsx | 2 - src/types/global.d.ts | 113 ++++++++++++++++++ 6 files changed, 129 insertions(+), 29 deletions(-) rename src/components/PageNation/{pageCount.style.jsx => pageCount.style.tsx} (89%) rename src/components/PageNation/{pageCount.jsx => pageCount.tsx} (74%) delete mode 100644 src/components/TestPage.jsx delete mode 100644 src/components/profile-favoriteCount/profile.favorite.jsx delete mode 100644 src/components/profile-favoriteCount/profile.favorite.style.jsx diff --git a/src/components/PageNation/pageCount.style.jsx b/src/components/PageNation/pageCount.style.tsx similarity index 89% rename from src/components/PageNation/pageCount.style.jsx rename to src/components/PageNation/pageCount.style.tsx index 949a5366..c4a52243 100644 --- a/src/components/PageNation/pageCount.style.jsx +++ b/src/components/PageNation/pageCount.style.tsx @@ -1,6 +1,10 @@ import styled from "styled-components"; import theme from "../../style/theme"; +export interface StyleProps { + page: number; + value: number; +} export const PageBtn = styled.div` display: flex; gap: 4px; @@ -9,7 +13,7 @@ export const PageBtn = styled.div` width: 304px; `; -export const Btn = styled.button` +export const Btn = styled.button` width: 40px; height: 40px; border-radius: 40px; diff --git a/src/components/PageNation/pageCount.jsx b/src/components/PageNation/pageCount.tsx similarity index 74% rename from src/components/PageNation/pageCount.jsx rename to src/components/PageNation/pageCount.tsx index 11fc665d..15a38031 100644 --- a/src/components/PageNation/pageCount.jsx +++ b/src/components/PageNation/pageCount.tsx @@ -1,9 +1,13 @@ -import { useState } from "react"; +import { MouseEvent, useState } from "react"; import * as S from "./pageCount.style"; import previousIcon from "../../assets/icons/previousPage.icon.svg"; import nextIcon from "../../assets/icons/nextPage.icon.svg"; // -export function PageButton({ page, value, onClick }) { + +interface Props extends S.StyleProps { + onClick: (e: MouseEvent | number) => void; +} +export function PageButton({ page, value, onClick }: Props) { return ( {value} @@ -11,14 +15,14 @@ export function PageButton({ page, value, onClick }) { ); } // -function PageCount({ page, onClick }) { +function PageCount({ page, onClick }: Props) { const BtnArray = [1, 2, 3, 4, 5]; const [currentPage, setCurrentPage] = useState(1); - const handleClickBtn = (e) => { - const currentPage = e.target.value; - setCurrentPage(currentPage); + const handleClickBtn = (btn: number) => { + setCurrentPage(btn); onClick(currentPage); }; + const handleClickPrev = () => { setCurrentPage(currentPage - 1); onClick(currentPage - 1); @@ -37,7 +41,7 @@ function PageCount({ page, onClick }) { return ( handleClickBtn(btn)} value={btn} page={page} /> diff --git a/src/components/TestPage.jsx b/src/components/TestPage.jsx deleted file mode 100644 index e6a3ccb4..00000000 --- a/src/components/TestPage.jsx +++ /dev/null @@ -1,19 +0,0 @@ -/// 컴포넌트 테스트 페이지 완료후 삭제 예정 - -// import Button from "./common/Button/Button"; -// import BtnHeart from "./common/BtnHeart/BtnHeart"; -// import Tag from "../components/Tag/Tag"; -// import { Input } from "./common/Input/Input"; -export default function TestPage() { - // //태그 테스트 배열 - // const tag3 = []; - // const tag1 = ["태그1", "태그2"]; - // const tags = ["태그1", "태그2", "태그3", "태그4"]; - return ( - <> - {/* - - */} - - ); -} diff --git a/src/components/profile-favoriteCount/profile.favorite.jsx b/src/components/profile-favoriteCount/profile.favorite.jsx deleted file mode 100644 index e69de29b..00000000 diff --git a/src/components/profile-favoriteCount/profile.favorite.style.jsx b/src/components/profile-favoriteCount/profile.favorite.style.jsx deleted file mode 100644 index e245c1ad..00000000 --- a/src/components/profile-favoriteCount/profile.favorite.style.jsx +++ /dev/null @@ -1,2 +0,0 @@ -import styled from "styled-components"; -import theme from "../../style/theme"; diff --git a/src/types/global.d.ts b/src/types/global.d.ts index 1453b24c..0006f2ea 100644 --- a/src/types/global.d.ts +++ b/src/types/global.d.ts @@ -54,3 +54,116 @@ export interface Comment { export interface Params { productId: string; } + +export interface Props { + src: string; +} + +//컴포넌트 부분 + +//commentCard +interface Props { + data: Comment; +} + +//btnheart +export interface StyledProps { + $small?: boolean; + $border?: boolean; + $items?: boolean; +} +interface Props extends S.StyledProps { + value: number; + active?: boolean; +} +//button +export interface ButtonProps { + $medium?: boolean; + $circle?: boolean; +} + +interface Props extends S.ButtonProps { + onClick: (e: MouseEvent) => void; + children: ReactNode; + disabled?: boolean; +} + +//input +export interface StyleProps { + $comment?: boolean; + $textArea?: boolean; + $edit?: boolean; +} + +interface Props extends S.StyleProps { + onChange: (e: ChangeEvent) => void; + label?: string; + placeholder?: string; + name: string; + tag?: boolean; + value?: string; + onKeyUp?: (e: React.KeyboardEvent) => void; + type?: "text" | "number" | "password" | "email"; +} + +interface ImgProps extends Omit { + onChange: (value: File | string) => void; +} +//select +type isOpen = { + $isOpen: boolean; +}; + +interface Props { + onChange: (option: string) => void; +} +//itemlist +interface Prop { + value: string; + items: Item[]; +} +interface ListItemProps { + value: string; + item: Item; +} + +interface Props { + value: string; + $device: string; +} + +interface Device { + gap: string; + gridTemplate: string; + gridRow: string; + height: string; +} + +interface DeviceStyle { + [key: string]: { + mobile: Device; + tablet: Device; + desktop: Device; + [key: string]: Device; + }; +} +//pageCount +interface Props extends S.StyleProps { + onClick: (e: MouseEvent | number) => void; +} +export interface StyleProps { + page: number; + value: number; +} +//tag +export interface StyledProps { + $product?: boolean; +} +interface DeleteButtonProps { + tag: string; + onClick?: () => void; +} +interface Props extends S.StyledProps { + tags: string[]; + onClick?: (tag: string) => void; +} From 8186da1b7a3a62afad6991bfb5daa0f28d84a554 Mon Sep 17 00:00:00 2001 From: nerte Date: Mon, 24 Feb 2025 16:14:18 +0900 Subject: [PATCH 27/38] [Type] create global type Params and ProductInfo --- src/api/product.api.tsx | 14 +++++--------- src/pages/AddItem/AddItem.tsx | 16 ++++------------ src/pages/ProductPage/Comments.tsx | 1 - src/pages/ProductPage/Product.tsx | 4 +--- src/pages/ProductPage/ProductInfo.tsx | 3 +-- src/types/global.d.ts | 22 +++++++--------------- 6 files changed, 18 insertions(+), 42 deletions(-) diff --git a/src/api/product.api.tsx b/src/api/product.api.tsx index 30955c2a..74b34e99 100644 --- a/src/api/product.api.tsx +++ b/src/api/product.api.tsx @@ -30,24 +30,20 @@ export async function bestProducts(device: string) { return body; } -export interface ProductInfo { +export interface ResponseData extends ProductInfo { createdAt: string; favoriteCount: number; ownerNickname: string; - ownerId: Number; - images: [string]; - tags: string[]; - price: number; + ownerId: number; description: string; - name: String; id: number; - isFavorite: Boolean; + isFavorite: boolean; } -export async function getProductInfo(productId: string) { +export async function getProductInfo({ productId }: Params) { try { const response = await axios.get(`${BASE_URL}/products/${productId}`); if (!response) throw new Error("제품정보 get api 실패"); - const data: ProductInfo = response.data; + const data: ResponseData = response.data; return data; } catch (error) { console.error(error, "제품정보 api 실패"); diff --git a/src/pages/AddItem/AddItem.tsx b/src/pages/AddItem/AddItem.tsx index 379ac521..5f5fc4e8 100644 --- a/src/pages/AddItem/AddItem.tsx +++ b/src/pages/AddItem/AddItem.tsx @@ -6,18 +6,10 @@ import Tag from "../../components/Tag/Tag"; import { ChangeEvent, useState } from "react"; // -interface Form { - img: string | File; - name: string; - content: string; - price: number; - tags: string[]; - [key: string]: string | File | number | string[]; -} -const INITIAL_DATA: Form = { - img: "", +const INITIAL_DATA: ProductInfo = { + images: "", name: "", - content: "", + description: "", price: 0, tags: [], }; @@ -33,7 +25,7 @@ function AddItem() { }; const handleImgChange = (value: File | string) => { - setFormData({ ...formData, img: value }); + setFormData({ ...formData, images: value }); }; const CreateTag = (e: React.KeyboardEvent) => { diff --git a/src/pages/ProductPage/Comments.tsx b/src/pages/ProductPage/Comments.tsx index a90afe31..8c152d29 100644 --- a/src/pages/ProductPage/Comments.tsx +++ b/src/pages/ProductPage/Comments.tsx @@ -11,7 +11,6 @@ import { getProductComments } from "../../api/comment.api.jsx"; import { Input } from "../../components/common/Input/Input.js"; import Button from "../../components/common/Button/Button.js"; import CommentCard from "../../components/CommentCard/CommentCard.jsx"; -import { Params } from "./Product.js"; // interface Writer { diff --git a/src/pages/ProductPage/Product.tsx b/src/pages/ProductPage/Product.tsx index 0948b07a..6c73be81 100644 --- a/src/pages/ProductPage/Product.tsx +++ b/src/pages/ProductPage/Product.tsx @@ -4,9 +4,7 @@ import ProductInfo from "./ProductInfo"; import Comments from "./Comments"; import * as S from "./Product.style"; // -export interface Params { - productId: string; -} + export default function Product() { const navigate = useNavigate(); const { productId } = useParams>(); diff --git a/src/pages/ProductPage/ProductInfo.tsx b/src/pages/ProductPage/ProductInfo.tsx index b7aa7b3b..d19313ca 100644 --- a/src/pages/ProductPage/ProductInfo.tsx +++ b/src/pages/ProductPage/ProductInfo.tsx @@ -8,10 +8,9 @@ import Tag from "../../components/Tag/Tag"; import BtnHeart from "../../components/common/BtnHeart/BtnHeart"; import { EditSelect } from "../../components/common/Select/Select"; import { useFormatDate, useFormatPrice } from "../../hooks/useFormatting"; -import { Params } from "./Product"; // -export default function ProductInfo({ productId }: Params) { +export default function ProductInfo(productId: Params) { const [product, setProduct] = useState(); const formattedDate = product ? useFormatDate(product.createdAt) diff --git a/src/types/global.d.ts b/src/types/global.d.ts index 0006f2ea..f815c68c 100644 --- a/src/types/global.d.ts +++ b/src/types/global.d.ts @@ -2,14 +2,10 @@ export {}; //전역 타입을 할 예정 declare global { - type Product = { - id: number; - name: string; - price: number; - }; + type Tag = string; - interface Window { - myGlobalVar: string; + interface Params { + productId: string; } } @@ -19,7 +15,7 @@ interface Form { name: string; content: string; price: number; - tags: string[]; + tags: Tag[]; [key: string]: string | File | number | string[]; } @@ -29,7 +25,7 @@ export interface Item { name: string; description: string; price: number; - tags: string[]; + tags: Tag[]; images: [string]; ownerId: number; favoriteCount: number; @@ -50,10 +46,6 @@ export interface Comment { content: string; id: number; } -//product -export interface Params { - productId: string; -} export interface Props { src: string; @@ -160,10 +152,10 @@ export interface StyledProps { $product?: boolean; } interface DeleteButtonProps { - tag: string; + tag: Tag; onClick?: () => void; } interface Props extends S.StyledProps { - tags: string[]; + tags: Tag[]; onClick?: (tag: string) => void; } From c5fea26e05bbb9e6cc242f22ac68b879a11eba9a Mon Sep 17 00:00:00 2001 From: nerte Date: Mon, 24 Feb 2025 18:04:15 +0900 Subject: [PATCH 28/38] [Type] add type for pageCount --- src/api/product.api.tsx | 7 ++-- src/components/PageNation/pageCount.style.tsx | 2 +- src/components/PageNation/pageCount.tsx | 10 ++++-- "src/pages/\bItemsPage/ItemsPage.tsx" | 7 ++-- src/pages/AddItem/AddItem.tsx | 8 ++--- src/pages/ProductPage/ProductInfo.tsx | 4 +-- src/types/global.d.ts | 35 +++++++------------ 7 files changed, 35 insertions(+), 38 deletions(-) diff --git a/src/api/product.api.tsx b/src/api/product.api.tsx index 74b34e99..7aa8d66d 100644 --- a/src/api/product.api.tsx +++ b/src/api/product.api.tsx @@ -1,6 +1,6 @@ import axios from "axios"; const BASE_URL = "https://panda-market-api.vercel.app"; - +// export async function getProducts({ device = "desktop", page = 1, @@ -18,7 +18,7 @@ export async function getProducts({ return body; } -export async function bestProducts(device: string) { +export async function bestProducts({ device }: Device) { const pageSize = device === "mobile" ? 1 : device === "tablet" ? 2 : 4; const response = await fetch( `${BASE_URL}/products?orderBy=favorite&pageSize=${pageSize}` @@ -30,7 +30,7 @@ export async function bestProducts(device: string) { return body; } -export interface ResponseData extends ProductInfo { +export interface ResponseData extends Product { createdAt: string; favoriteCount: number; ownerNickname: string; @@ -39,6 +39,7 @@ export interface ResponseData extends ProductInfo { id: number; isFavorite: boolean; } + export async function getProductInfo({ productId }: Params) { try { const response = await axios.get(`${BASE_URL}/products/${productId}`); diff --git a/src/components/PageNation/pageCount.style.tsx b/src/components/PageNation/pageCount.style.tsx index c4a52243..fe1f94b6 100644 --- a/src/components/PageNation/pageCount.style.tsx +++ b/src/components/PageNation/pageCount.style.tsx @@ -3,7 +3,7 @@ import theme from "../../style/theme"; export interface StyleProps { page: number; - value: number; + value?: number; } export const PageBtn = styled.div` display: flex; diff --git a/src/components/PageNation/pageCount.tsx b/src/components/PageNation/pageCount.tsx index 15a38031..251506b0 100644 --- a/src/components/PageNation/pageCount.tsx +++ b/src/components/PageNation/pageCount.tsx @@ -5,7 +5,7 @@ import nextIcon from "../../assets/icons/nextPage.icon.svg"; // interface Props extends S.StyleProps { - onClick: (e: MouseEvent | number) => void; + onClick: (e: MouseEvent) => void; } export function PageButton({ page, value, onClick }: Props) { return ( @@ -15,12 +15,16 @@ export function PageButton({ page, value, onClick }: Props) { ); } // -function PageCount({ page, onClick }: Props) { +type PageCountProps = Omit & { + onClick: (btn: number) => void; +}; +function PageCount({ page, onClick }: PageCountProps) { const BtnArray = [1, 2, 3, 4, 5]; const [currentPage, setCurrentPage] = useState(1); + const handleClickBtn = (btn: number) => { setCurrentPage(btn); - onClick(currentPage); + onClick(btn); }; const handleClickPrev = () => { diff --git "a/src/pages/\bItemsPage/ItemsPage.tsx" "b/src/pages/\bItemsPage/ItemsPage.tsx" index 17528919..520995eb 100644 --- "a/src/pages/\bItemsPage/ItemsPage.tsx" +++ "b/src/pages/\bItemsPage/ItemsPage.tsx" @@ -4,13 +4,14 @@ import { useNavigate } from "react-router-dom"; import * as S from "./ItemsPage.style"; import ItemsList from "../../components/ItemsList/ItemsList"; import { getProducts, bestProducts } from "../../api/product.api"; -import PageCount from "../../components/PageNation/pageCount"; //ToDo -import useWindowSize from "../../hooks/useWindowSize"; //Todo +import PageCount from "../../components/PageNation/pageCount"; +import useWindowSize from "../../hooks/useWindowSize"; import { SortSelect } from "../../components/common/Select/Select"; import Button from "../../components/common/Button/Button"; import { SearchInput } from "../../components/common/Input/Input"; // -export interface Item { + +export interface Item extends Omit { id: number; name: string; description: string; diff --git a/src/pages/AddItem/AddItem.tsx b/src/pages/AddItem/AddItem.tsx index 5f5fc4e8..1a0ea84e 100644 --- a/src/pages/AddItem/AddItem.tsx +++ b/src/pages/AddItem/AddItem.tsx @@ -4,9 +4,10 @@ import * as I from "../../components/common/Input/Input"; import * as S from "./AddItem.style"; import Tag from "../../components/Tag/Tag"; import { ChangeEvent, useState } from "react"; - // -const INITIAL_DATA: ProductInfo = { +type ProductForm = Omit & { images: string | File }; + +const INITIAL_DATA: ProductForm = { images: "", name: "", description: "", @@ -43,7 +44,7 @@ function AddItem() { }; const handleClickTagDelete = (tag: string) => { - const filterTags = formData.tags.filter((prev) => prev !== tag); + const filterTags = formData.tags.filter((prev: string) => prev !== tag); setFormData((prev) => ({ ...prev, tags: filterTags })); }; @@ -83,7 +84,6 @@ function AddItem() { placeholder={placeholder.img} onChange={handleImgChange} /> - (); + const [product, setProduct] = useState(); const formattedDate = product ? useFormatDate(product.createdAt) : "날짜 없음"; diff --git a/src/types/global.d.ts b/src/types/global.d.ts index f815c68c..73bb6b4f 100644 --- a/src/types/global.d.ts +++ b/src/types/global.d.ts @@ -7,31 +7,22 @@ declare global { interface Params { productId: string; } -} + interface Device { + device: string; + } -//addItem -interface Form { - img: string | File; - name: string; - content: string; - price: number; - tags: Tag[]; - [key: string]: string | File | number | string[]; + interface Product { + name: string; + price: number; + tags: Tag[]; + images: [string]; + description: string; + [key: string]: any; + //원래 any 부분에 string| boolean| [string]|number 를 적었었는데, + //이터러블이 아닌 값이 섞여있어서 includes랑 ...prev가 안되더라고요... ㅠㅠ + } } -//itemsPage -export interface Item { - id: number; - name: string; - description: string; - price: number; - tags: Tag[]; - images: [string]; - ownerId: number; - favoriteCount: number; - createdAt: Date; - updatedAt: Date; -} //comment interface Writer { image: string; From de5324686f75d09a19bf596caadcd2a5d91e277c Mon Sep 17 00:00:00 2001 From: nerte Date: Mon, 24 Feb 2025 18:10:16 +0900 Subject: [PATCH 29/38] [Type] create Item type with Omit --- src/api/product.api.tsx | 1 - "src/pages/\bItemsPage/ItemsPage.tsx" | 15 ++------------- src/types/global.d.ts | 2 +- 3 files changed, 3 insertions(+), 15 deletions(-) diff --git a/src/api/product.api.tsx b/src/api/product.api.tsx index 7aa8d66d..1fdf74cc 100644 --- a/src/api/product.api.tsx +++ b/src/api/product.api.tsx @@ -35,7 +35,6 @@ export interface ResponseData extends Product { favoriteCount: number; ownerNickname: string; ownerId: number; - description: string; id: number; isFavorite: boolean; } diff --git "a/src/pages/\bItemsPage/ItemsPage.tsx" "b/src/pages/\bItemsPage/ItemsPage.tsx" index 520995eb..6773dcd2 100644 --- "a/src/pages/\bItemsPage/ItemsPage.tsx" +++ "b/src/pages/\bItemsPage/ItemsPage.tsx" @@ -3,7 +3,7 @@ import { useNavigate } from "react-router-dom"; // import * as S from "./ItemsPage.style"; import ItemsList from "../../components/ItemsList/ItemsList"; -import { getProducts, bestProducts } from "../../api/product.api"; +import { getProducts, bestProducts, ResponseData } from "../../api/product.api"; import PageCount from "../../components/PageNation/pageCount"; import useWindowSize from "../../hooks/useWindowSize"; import { SortSelect } from "../../components/common/Select/Select"; @@ -11,18 +11,7 @@ import Button from "../../components/common/Button/Button"; import { SearchInput } from "../../components/common/Input/Input"; // -export interface Item extends Omit { - id: number; - name: string; - description: string; - price: number; - tags: string[]; - images: [string]; - ownerId: number; - favoriteCount: number; - createdAt: Date; - updatedAt: Date; -} +type Item = Omit; // export const INITIAL_ITEM: Item[] = []; function HomePage() { diff --git a/src/types/global.d.ts b/src/types/global.d.ts index 73bb6b4f..3432cb0c 100644 --- a/src/types/global.d.ts +++ b/src/types/global.d.ts @@ -10,7 +10,7 @@ declare global { interface Device { device: string; } - + type Device = string; interface Product { name: string; price: number; From 6352933ef381a09f35ebf376de5ad15b31cb4598 Mon Sep 17 00:00:00 2001 From: nerte Date: Mon, 24 Feb 2025 18:26:46 +0900 Subject: [PATCH 30/38] =?UTF-8?q?[Type]=20Comment=20interface=20=EC=A0=84?= =?UTF-8?q?=EC=97=AD=20=ED=83=80=EC=9E=85=20=EC=84=A4=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/CommentCard/CommentCard.tsx | 2 +- src/components/Tag/Tag.style.tsx | 2 +- src/components/Tag/Tag.tsx | 4 +- src/pages/ProductPage/Comments.tsx | 14 ----- src/types/global.d.ts | 67 +++++----------------- 5 files changed, 19 insertions(+), 70 deletions(-) diff --git a/src/components/CommentCard/CommentCard.tsx b/src/components/CommentCard/CommentCard.tsx index b8854f64..87db0591 100644 --- a/src/components/CommentCard/CommentCard.tsx +++ b/src/components/CommentCard/CommentCard.tsx @@ -6,8 +6,8 @@ import { Input } from "../common/Input/Input.js"; import { EditSelect } from "../common/Select/Select.js"; import { button } from "../../constants/globalConstant.jsx"; import { useFormatUpDate } from "../../hooks/useFormatting.jsx"; -import { Comment } from "../../pages/ProductPage/Comments.js"; // + interface Props { data: Comment; } diff --git a/src/components/Tag/Tag.style.tsx b/src/components/Tag/Tag.style.tsx index 03865ea0..f1c20ec0 100644 --- a/src/components/Tag/Tag.style.tsx +++ b/src/components/Tag/Tag.style.tsx @@ -5,7 +5,7 @@ export interface StyledProps { $product?: boolean; } interface DeleteButtonProps { - tag: string; + tag: Tag; onClick?: () => void; } export const TagsContainer = styled.div` diff --git a/src/components/Tag/Tag.tsx b/src/components/Tag/Tag.tsx index 5bc9a9da..ca00dbbd 100644 --- a/src/components/Tag/Tag.tsx +++ b/src/components/Tag/Tag.tsx @@ -2,8 +2,8 @@ import DeleteButton from "../../assets/icons/DeleteIcon.svg"; import * as S from "./Tag.style"; // interface Props extends S.StyledProps { - tags: string[]; - onClick?: (tag: string) => void; + tags: Tag[]; + onClick?: (tag: Tag) => void; } export default function Tag({ tags, ...props }: Props) { const { onClick, ...rest } = props; diff --git a/src/pages/ProductPage/Comments.tsx b/src/pages/ProductPage/Comments.tsx index 8c152d29..09ca1cf4 100644 --- a/src/pages/ProductPage/Comments.tsx +++ b/src/pages/ProductPage/Comments.tsx @@ -13,20 +13,6 @@ import Button from "../../components/common/Button/Button.js"; import CommentCard from "../../components/CommentCard/CommentCard.jsx"; // -interface Writer { - image: string; - nickname: string; - id: number; -} - -export interface Comment { - writer: Writer; - updatedAt: string; - createdAt: string; - content: string; - id: number; -} - export default function Comments({ productId }: Params) { const [isDisabled, setIsDisabled] = useState(true); const [comments, setComments] = useState([]); diff --git a/src/types/global.d.ts b/src/types/global.d.ts index 3432cb0c..29161946 100644 --- a/src/types/global.d.ts +++ b/src/types/global.d.ts @@ -10,7 +10,6 @@ declare global { interface Device { device: string; } - type Device = string; interface Product { name: string; price: number; @@ -19,23 +18,20 @@ declare global { description: string; [key: string]: any; //원래 any 부분에 string| boolean| [string]|number 를 적었었는데, - //이터러블이 아닌 값이 섞여있어서 includes랑 ...prev가 안되더라고요... ㅠㅠ + //유니온 타입에 이터러블이 아닌 값이 섞여있어서 includes랑 ...prev가 안되더라고요... ㅠㅠ + } + interface Writer { + image: string; + nickname: string; + id: number; + } + interface Comment { + writer: Writer; + updatedAt: string; + createdAt: string; + content: string; + id: number; } -} - -//comment -interface Writer { - image: string; - nickname: string; - id: number; -} - -export interface Comment { - writer: Writer; - updatedAt: string; - createdAt: string; - content: string; - id: number; } export interface Props { @@ -50,20 +46,12 @@ interface Props { } //btnheart -export interface StyledProps { - $small?: boolean; - $border?: boolean; - $items?: boolean; -} + interface Props extends S.StyledProps { value: number; active?: boolean; } //button -export interface ButtonProps { - $medium?: boolean; - $circle?: boolean; -} interface Props extends S.ButtonProps { onClick: (e: MouseEvent) => void; @@ -72,11 +60,6 @@ interface Props extends S.ButtonProps { } //input -export interface StyleProps { - $comment?: boolean; - $textArea?: boolean; - $edit?: boolean; -} interface Props extends S.StyleProps { onChange: (e: ChangeEvent) => void; @@ -93,9 +76,6 @@ interface ImgProps extends Omit { onChange: (value: File | string) => void; } //select -type isOpen = { - $isOpen: boolean; -}; interface Props { onChange: (option: string) => void; @@ -115,21 +95,6 @@ interface Props { $device: string; } -interface Device { - gap: string; - gridTemplate: string; - gridRow: string; - height: string; -} - -interface DeviceStyle { - [key: string]: { - mobile: Device; - tablet: Device; - desktop: Device; - [key: string]: Device; - }; -} //pageCount interface Props extends S.StyleProps { onClick: (e: MouseEvent | number) => void; @@ -139,9 +104,7 @@ export interface StyleProps { value: number; } //tag -export interface StyledProps { - $product?: boolean; -} + interface DeleteButtonProps { tag: Tag; onClick?: () => void; From d0b343e159aaeeac87ada8e98f1b1cd72e7ae1f5 Mon Sep 17 00:00:00 2001 From: nerte Date: Mon, 24 Feb 2025 18:32:41 +0900 Subject: [PATCH 31/38] =?UTF-8?q?[Type]=20onClick=20type=20=EC=83=9D?= =?UTF-8?q?=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/components/PageNation/pageCount.tsx | 2 +- src/components/common/Button/Button.tsx | 4 +- src/types/global.d.ts | 82 +------------------------ 3 files changed, 4 insertions(+), 84 deletions(-) diff --git a/src/components/PageNation/pageCount.tsx b/src/components/PageNation/pageCount.tsx index 251506b0..9047be0c 100644 --- a/src/components/PageNation/pageCount.tsx +++ b/src/components/PageNation/pageCount.tsx @@ -5,7 +5,7 @@ import nextIcon from "../../assets/icons/nextPage.icon.svg"; // interface Props extends S.StyleProps { - onClick: (e: MouseEvent) => void; + onClick: onClick; } export function PageButton({ page, value, onClick }: Props) { return ( diff --git a/src/components/common/Button/Button.tsx b/src/components/common/Button/Button.tsx index 0773bf2c..dc641677 100644 --- a/src/components/common/Button/Button.tsx +++ b/src/components/common/Button/Button.tsx @@ -1,10 +1,10 @@ import * as S from "./Button.style"; -import { ReactNode, MouseEvent } from "react"; +import { ReactNode } from "react"; // interface Props extends S.ButtonProps { - onClick: (e: MouseEvent) => void; + onClick: onClick; children: ReactNode; disabled?: boolean; } diff --git a/src/types/global.d.ts b/src/types/global.d.ts index 29161946..8f5f3bfc 100644 --- a/src/types/global.d.ts +++ b/src/types/global.d.ts @@ -1,6 +1,5 @@ export {}; -//전역 타입을 할 예정 declare global { type Tag = string; @@ -32,84 +31,5 @@ declare global { content: string; id: number; } -} - -export interface Props { - src: string; -} - -//컴포넌트 부분 - -//commentCard -interface Props { - data: Comment; -} - -//btnheart - -interface Props extends S.StyledProps { - value: number; - active?: boolean; -} -//button - -interface Props extends S.ButtonProps { - onClick: (e: MouseEvent) => void; - children: ReactNode; - disabled?: boolean; -} - -//input - -interface Props extends S.StyleProps { - onChange: (e: ChangeEvent) => void; - label?: string; - placeholder?: string; - name: string; - tag?: boolean; - value?: string; - onKeyUp?: (e: React.KeyboardEvent) => void; - type?: "text" | "number" | "password" | "email"; -} - -interface ImgProps extends Omit { - onChange: (value: File | string) => void; -} -//select - -interface Props { - onChange: (option: string) => void; -} -//itemlist -interface Prop { - value: string; - items: Item[]; -} -interface ListItemProps { - value: string; - item: Item; -} - -interface Props { - value: string; - $device: string; -} - -//pageCount -interface Props extends S.StyleProps { - onClick: (e: MouseEvent | number) => void; -} -export interface StyleProps { - page: number; - value: number; -} -//tag - -interface DeleteButtonProps { - tag: Tag; - onClick?: () => void; -} -interface Props extends S.StyledProps { - tags: Tag[]; - onClick?: (tag: string) => void; + type onClick = (e: MouseEvent) => void; } From 7e56e151f84a73239bd83740a61bb84152fb0110 Mon Sep 17 00:00:00 2001 From: nerte Date: Mon, 24 Feb 2025 18:37:16 +0900 Subject: [PATCH 32/38] [Refactor] fetch ->axios --- src/api/product.api.tsx | 34 +++++++++++++++++++++------------- 1 file changed, 21 insertions(+), 13 deletions(-) diff --git a/src/api/product.api.tsx b/src/api/product.api.tsx index 1fdf74cc..23ec8d0c 100644 --- a/src/api/product.api.tsx +++ b/src/api/product.api.tsx @@ -1,7 +1,8 @@ import axios from "axios"; const BASE_URL = "https://panda-market-api.vercel.app"; // -export async function getProducts({ + +export async function getProduct({ device = "desktop", page = 1, selectedOrder = "최신순", @@ -9,25 +10,32 @@ export async function getProducts({ const order = selectedOrder === "최신순" ? "recent" : "favorite"; const pageSize = device === "mobile" ? 4 : device === "tablet" ? 6 : 10; const query = `?orderBy=${order}&page=${page}&pageSize=${pageSize}`; - const response = await fetch(`${BASE_URL}/products${query}`); - if (!response.ok) { - throw new Error("상품을 불러오지 못했습니다. 다시 시도해주세요"); + try { + const res = await axios.get(`${BASE_URL}/products${query}`); + if (!res) throw new Error("상품 불러오기 실패"); + const data = res.data; + return data; + } catch (error) { + console.error(error, "상품 불러오기 실패"); } - const body = await response.json(); - return body; } export async function bestProducts({ device }: Device) { const pageSize = device === "mobile" ? 1 : device === "tablet" ? 2 : 4; - const response = await fetch( - `${BASE_URL}/products?orderBy=favorite&pageSize=${pageSize}` - ); - if (!response.ok) { - throw new Error("베스트 상품을 불러오지 못했습니다. 다시 시도해주세요"); + try { + const res = await axios.get( + `${BASE_URL}/products?orderBy=favorite&pageSize=${pageSize}` + ); + if (!res) throw new Error("베스트상품 api 실패"); + const data = res.data; + return data; + } catch (error) { + console.error( + error, + "베스트 상품을 불러오지 못했습니다. 다시 시도해주세요" + ); } - const body = await response.json(); - return body; } export interface ResponseData extends Product { From a4011fe8d1a3d76fc7cedfa781bc6a7d536767f6 Mon Sep 17 00:00:00 2001 From: nerte Date: Mon, 24 Feb 2025 18:51:13 +0900 Subject: [PATCH 33/38] [Type] product.api interface --- src/api/product.api.tsx | 25 +++++++++++++------------ "src/pages/\bItemsPage/ItemsPage.tsx" | 18 +++++++----------- src/types/global.d.ts | 1 + 3 files changed, 21 insertions(+), 23 deletions(-) diff --git a/src/api/product.api.tsx b/src/api/product.api.tsx index 23ec8d0c..4bd09e66 100644 --- a/src/api/product.api.tsx +++ b/src/api/product.api.tsx @@ -2,7 +2,17 @@ import axios from "axios"; const BASE_URL = "https://panda-market-api.vercel.app"; // -export async function getProduct({ +export interface ResponseData extends Product { + createdAt: string; + favoriteCount: number; + ownerNickname: string; + ownerId: number; + id: number; + isFavorite: boolean; +} +export type Items = Omit; + +export async function getProducts({ device = "desktop", page = 1, selectedOrder = "최신순", @@ -14,7 +24,7 @@ export async function getProduct({ try { const res = await axios.get(`${BASE_URL}/products${query}`); if (!res) throw new Error("상품 불러오기 실패"); - const data = res.data; + const data: Items[] = res.data.list; return data; } catch (error) { console.error(error, "상품 불러오기 실패"); @@ -28,7 +38,7 @@ export async function bestProducts({ device }: Device) { `${BASE_URL}/products?orderBy=favorite&pageSize=${pageSize}` ); if (!res) throw new Error("베스트상품 api 실패"); - const data = res.data; + const data: Items[] = res.data.list; return data; } catch (error) { console.error( @@ -38,15 +48,6 @@ export async function bestProducts({ device }: Device) { } } -export interface ResponseData extends Product { - createdAt: string; - favoriteCount: number; - ownerNickname: string; - ownerId: number; - id: number; - isFavorite: boolean; -} - export async function getProductInfo({ productId }: Params) { try { const response = await axios.get(`${BASE_URL}/products/${productId}`); diff --git "a/src/pages/\bItemsPage/ItemsPage.tsx" "b/src/pages/\bItemsPage/ItemsPage.tsx" index 6773dcd2..047f2989 100644 --- "a/src/pages/\bItemsPage/ItemsPage.tsx" +++ "b/src/pages/\bItemsPage/ItemsPage.tsx" @@ -3,21 +3,17 @@ import { useNavigate } from "react-router-dom"; // import * as S from "./ItemsPage.style"; import ItemsList from "../../components/ItemsList/ItemsList"; -import { getProducts, bestProducts, ResponseData } from "../../api/product.api"; +import * as A from "../../api/product.api"; import PageCount from "../../components/PageNation/pageCount"; import useWindowSize from "../../hooks/useWindowSize"; import { SortSelect } from "../../components/common/Select/Select"; import Button from "../../components/common/Button/Button"; import { SearchInput } from "../../components/common/Input/Input"; // - -type Item = Omit; -// -export const INITIAL_ITEM: Item[] = []; function HomePage() { - const [items, setItems] = useState(INITIAL_ITEM); + const [items, setItems] = useState([]); const [selectedOrder, setSelectedOrder] = useState("최신순"); - const [bestItems, setBestItems] = useState(INITIAL_ITEM); + const [bestItems, setBestItems] = useState([]); const [page, setPage] = useState(1); const device = useWindowSize(); // useWindow 타입 지정해주기 const navigate = useNavigate(); @@ -31,10 +27,10 @@ function HomePage() { device: string; page: number; }) => { - const { list: bestItems } = await bestProducts(options); - const { list } = await getProducts(options); - setItems(list); - setBestItems(bestItems); + const bestItems = await A.bestProducts(options); + const list = await A.getProducts(options); + setItems(list ?? []); + setBestItems(bestItems ?? []); }; const handleClickPageChange = (value: number) => { diff --git a/src/types/global.d.ts b/src/types/global.d.ts index 8f5f3bfc..6a2b8fca 100644 --- a/src/types/global.d.ts +++ b/src/types/global.d.ts @@ -9,6 +9,7 @@ declare global { interface Device { device: string; } + interface Product { name: string; price: number; From 3ee9850e37b2b6e7498dcf8283cf15cb51c9efe2 Mon Sep 17 00:00:00 2001 From: nerte Date: Mon, 24 Feb 2025 18:58:49 +0900 Subject: [PATCH 34/38] =?UTF-8?q?[Chore]=20=EB=8B=A8=EC=88=9C=20=EC=98=A4?= =?UTF-8?q?=ED=83=80=20=EC=97=90=EB=9F=AC=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api/{comment.api.jsx => comment.api.tsx} | 6 +++--- src/pages/ProductPage/Comments.tsx | 4 ++-- src/pages/ProductPage/ProductInfo.tsx | 4 ++-- 3 files changed, 7 insertions(+), 7 deletions(-) rename src/api/{comment.api.jsx => comment.api.tsx} (70%) diff --git a/src/api/comment.api.jsx b/src/api/comment.api.tsx similarity index 70% rename from src/api/comment.api.jsx rename to src/api/comment.api.tsx index 0e14ef63..88859589 100644 --- a/src/api/comment.api.jsx +++ b/src/api/comment.api.tsx @@ -1,7 +1,7 @@ import axios from "axios"; const BASE_URL = "https://panda-market-api.vercel.app"; -export async function getProductComments(productId, limit = 3) { +export async function getProductComments(productId: Params, limit = 3) { try { const res = await axios.get( `${BASE_URL}/products/${productId}/comments?limit=${limit}` @@ -9,9 +9,9 @@ export async function getProductComments(productId, limit = 3) { if (!res) { throw new Error("리뷰 불러오기 실패"); } - return res.data.list; + const data: Comment[] = res.data.list; + return data; } catch (error) { console.error(error); - return null; } } diff --git a/src/pages/ProductPage/Comments.tsx b/src/pages/ProductPage/Comments.tsx index 09ca1cf4..284d8003 100644 --- a/src/pages/ProductPage/Comments.tsx +++ b/src/pages/ProductPage/Comments.tsx @@ -19,8 +19,8 @@ export default function Comments({ productId }: Params) { // const [formData, setFormData] = useState(""); const navigate = useNavigate(); const handleLoad = async () => { - const data = await getProductComments(productId); - setComments(data); + const data = await getProductComments({ productId }); + setComments(data ?? []); }; const handleChange = () => { setIsDisabled(false); diff --git a/src/pages/ProductPage/ProductInfo.tsx b/src/pages/ProductPage/ProductInfo.tsx index 211a75c5..cba092d0 100644 --- a/src/pages/ProductPage/ProductInfo.tsx +++ b/src/pages/ProductPage/ProductInfo.tsx @@ -10,7 +10,7 @@ import { EditSelect } from "../../components/common/Select/Select"; import { useFormatDate, useFormatPrice } from "../../hooks/useFormatting"; // -export default function ProductInfo(productId: Params) { +export default function ProductInfo({ productId }: Params) { const [product, setProduct] = useState(); const formattedDate = product ? useFormatDate(product.createdAt) @@ -21,7 +21,7 @@ export default function ProductInfo(productId: Params) { // const handleLoad = async () => { - const info = await getProductInfo(productId); + const info = await getProductInfo({ productId }); setProduct(info); }; From 6dc1fab96010fc6b97b8ceb019b604eb8fb407a7 Mon Sep 17 00:00:00 2001 From: nerte Date: Mon, 24 Feb 2025 19:02:19 +0900 Subject: [PATCH 35/38] =?UTF-8?q?[Chore]=20type=20items=20->=20item=20?= =?UTF-8?q?=EC=9C=BC=EB=A1=9C=20=EC=9D=B4=EB=A6=84=20=EB=B3=80=EA=B2=BD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api/product.api.tsx | 6 +++--- src/components/ItemsList/ItemsList.tsx | 2 +- "src/pages/\bItemsPage/ItemsPage.tsx" | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/api/product.api.tsx b/src/api/product.api.tsx index 4bd09e66..0ff07fb8 100644 --- a/src/api/product.api.tsx +++ b/src/api/product.api.tsx @@ -10,7 +10,7 @@ export interface ResponseData extends Product { id: number; isFavorite: boolean; } -export type Items = Omit; +export type Item = Omit; export async function getProducts({ device = "desktop", @@ -24,7 +24,7 @@ export async function getProducts({ try { const res = await axios.get(`${BASE_URL}/products${query}`); if (!res) throw new Error("상품 불러오기 실패"); - const data: Items[] = res.data.list; + const data: Item[] = res.data.list; return data; } catch (error) { console.error(error, "상품 불러오기 실패"); @@ -38,7 +38,7 @@ export async function bestProducts({ device }: Device) { `${BASE_URL}/products?orderBy=favorite&pageSize=${pageSize}` ); if (!res) throw new Error("베스트상품 api 실패"); - const data: Items[] = res.data.list; + const data: Item[] = res.data.list; return data; } catch (error) { console.error( diff --git a/src/components/ItemsList/ItemsList.tsx b/src/components/ItemsList/ItemsList.tsx index 3f94782d..2783ef1a 100644 --- a/src/components/ItemsList/ItemsList.tsx +++ b/src/components/ItemsList/ItemsList.tsx @@ -3,7 +3,7 @@ import useWindowSize from "../../hooks/useWindowSize"; // import * as S from "./ItemsList.style"; import BtnHeart from "../common/BtnHeart/BtnHeart"; -import { Item } from "../../pages/ItemsPage/ItemsPage"; +import { Item } from "../../api/product.api"; // interface Prop { diff --git "a/src/pages/\bItemsPage/ItemsPage.tsx" "b/src/pages/\bItemsPage/ItemsPage.tsx" index 047f2989..3d7f4cab 100644 --- "a/src/pages/\bItemsPage/ItemsPage.tsx" +++ "b/src/pages/\bItemsPage/ItemsPage.tsx" @@ -11,9 +11,9 @@ import Button from "../../components/common/Button/Button"; import { SearchInput } from "../../components/common/Input/Input"; // function HomePage() { - const [items, setItems] = useState([]); + const [items, setItems] = useState([]); const [selectedOrder, setSelectedOrder] = useState("최신순"); - const [bestItems, setBestItems] = useState([]); + const [bestItems, setBestItems] = useState([]); const [page, setPage] = useState(1); const device = useWindowSize(); // useWindow 타입 지정해주기 const navigate = useNavigate(); From b4c2a291eec02504de300c25dba9c8e97424e673 Mon Sep 17 00:00:00 2001 From: nerte Date: Mon, 24 Feb 2025 19:08:47 +0900 Subject: [PATCH 36/38] =?UTF-8?q?[Chore]=20=EC=9E=98=20=EB=AA=A8=EB=A5=B4?= =?UTF-8?q?=EA=B2=A0=EB=8A=94=20=EB=B6=80=EB=B6=84=20=EC=A3=BC=EC=84=9D=20?= =?UTF-8?q?=EB=82=A8=EA=B9=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/AddItem/AddItem.tsx | 2 +- src/types/global.d.ts | 3 ++- 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/pages/AddItem/AddItem.tsx b/src/pages/AddItem/AddItem.tsx index 1a0ea84e..911349d2 100644 --- a/src/pages/AddItem/AddItem.tsx +++ b/src/pages/AddItem/AddItem.tsx @@ -49,7 +49,7 @@ function AddItem() { }; const isInputValid = REQUIRED_INPUT.every((field) => { - const value = formData[field]; + const value = formData[field]; //전역 타입 파일에 주석 단부분에서 인덱스 시그니쳐를 지우면 이부분이 오류가 납니다 ㅠㅠ switch (typeof value) { case "object": if (Array.isArray(value) && value.length === 0) { diff --git a/src/types/global.d.ts b/src/types/global.d.ts index 6a2b8fca..bfd0b615 100644 --- a/src/types/global.d.ts +++ b/src/types/global.d.ts @@ -18,7 +18,8 @@ declare global { description: string; [key: string]: any; //원래 any 부분에 string| boolean| [string]|number 를 적었었는데, - //유니온 타입에 이터러블이 아닌 값이 섞여있어서 includes랑 ...prev가 안되더라고요... ㅠㅠ + //유니온 타입에 이터러블이 아닌 값이 섞여있어서 includes랑 스프레드가 안되더라고요... ㅠㅠ + //인덱스 시그니쳐를 지우면 addItem 에서 에러가 나서 방법을 찾아보다가 도저히 모르겠어서 any 로 지정했습니다! (addItem에 에러 부분 주석 남겨놨습니다!) } interface Writer { image: string; From b562007e443a2ae402b76a1d7e7bef8b9364524f Mon Sep 17 00:00:00 2001 From: nerte Date: Mon, 24 Feb 2025 19:17:38 +0900 Subject: [PATCH 37/38] =?UTF-8?q?[Chore]=20npm=20run=20start=20=EC=97=90?= =?UTF-8?q?=EB=9F=AC=20=EA=B2=BD=EB=A1=9C=EB=AC=B8=EC=A0=9C=20=EC=88=98?= =?UTF-8?q?=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/Main.jsx | 6 ++---- src/components/CommentCard/CommentCard.tsx | 6 +++--- src/pages/ProductPage/Comments.tsx | 10 +++++----- src/pages/ProductPage/ProductInfo.tsx | 12 ++++-------- 4 files changed, 14 insertions(+), 20 deletions(-) diff --git a/src/Main.jsx b/src/Main.jsx index 9b73ebec..0b4bf2d1 100644 --- a/src/Main.jsx +++ b/src/Main.jsx @@ -4,9 +4,8 @@ import GlobalStyle from "./style/globalStyle.js"; import LandingPage from "./pages/LandingPage/LandingPage.jsx"; import App from "./App.js"; import ItemsPage from "./pages/ItemsPage/ItemsPage.tsx"; -import AddItem from "./pages/AddItem/AddItem.jsx"; -import Product from "./pages/ProductPage/Product.jsx"; -import Test from "./components/TestPage.jsx"; +import AddItem from "./pages/AddItem/AddItem.tsx"; +import Product from "./pages/ProductPage/Product.tsx"; // function Main() { return ( @@ -16,7 +15,6 @@ function Main() { } /> }> - } /> } /> } /> } /> diff --git a/src/components/CommentCard/CommentCard.tsx b/src/components/CommentCard/CommentCard.tsx index 87db0591..8baadc4a 100644 --- a/src/components/CommentCard/CommentCard.tsx +++ b/src/components/CommentCard/CommentCard.tsx @@ -1,9 +1,9 @@ import { useEffect, useState } from "react"; // -import * as S from "./CommentCard.style.js"; +import * as S from "./CommentCard.style"; import defaultImg from "../../assets/icons/default.profile.icon.svg"; -import { Input } from "../common/Input/Input.js"; -import { EditSelect } from "../common/Select/Select.js"; +import { Input } from "../common/Input/Input"; +import { EditSelect } from "../common/Select/Select"; import { button } from "../../constants/globalConstant.jsx"; import { useFormatUpDate } from "../../hooks/useFormatting.jsx"; // diff --git a/src/pages/ProductPage/Comments.tsx b/src/pages/ProductPage/Comments.tsx index 284d8003..311cc89f 100644 --- a/src/pages/ProductPage/Comments.tsx +++ b/src/pages/ProductPage/Comments.tsx @@ -1,16 +1,16 @@ import { useState, useEffect } from "react"; import { useNavigate } from "react-router-dom"; // -import * as S from "./Comments.style.js"; +import * as S from "./Comments.style"; import { placeholder } from "../../constants/globalConstant.jsx"; import { button } from "../../constants/globalConstant.jsx"; import noComment from "../../assets/no-comments.svg"; import returnIcon from "../../assets/icons/return.icon.svg"; // -import { getProductComments } from "../../api/comment.api.jsx"; -import { Input } from "../../components/common/Input/Input.js"; -import Button from "../../components/common/Button/Button.js"; -import CommentCard from "../../components/CommentCard/CommentCard.jsx"; +import { getProductComments } from "../../api/comment.api"; +import { Input } from "../../components/common/Input/Input"; +import Button from "../../components/common/Button/Button"; +import CommentCard from "../../components/CommentCard/CommentCard"; // export default function Comments({ productId }: Params) { diff --git a/src/pages/ProductPage/ProductInfo.tsx b/src/pages/ProductPage/ProductInfo.tsx index cba092d0..ec93516b 100644 --- a/src/pages/ProductPage/ProductInfo.tsx +++ b/src/pages/ProductPage/ProductInfo.tsx @@ -12,12 +12,8 @@ import { useFormatDate, useFormatPrice } from "../../hooks/useFormatting"; export default function ProductInfo({ productId }: Params) { const [product, setProduct] = useState(); - const formattedDate = product - ? useFormatDate(product.createdAt) - : "날짜 없음"; - const formattedPrice = product - ? useFormatPrice(product.price, "KRW") - : "가격 없음"; + const formattedDate = useFormatDate(product?.createdAt || ""); + const formattedPrice = useFormatPrice(product?.price || 0, "KRW"); // const handleLoad = async () => { @@ -45,7 +41,7 @@ export default function ProductInfo({ productId }: Params) { {product?.name ?? "상품 이름 없음"} - {formattedPrice}원 + {formattedPrice || 0}원 @@ -67,7 +63,7 @@ export default function ProductInfo({ productId }: Params) {
    {product?.ownerNickname ?? "닉네임"} - {formattedDate} + {formattedDate || "날짜 정보 없음"}
    From cd7f584aca93a39ba330cee1ce997e5922c1a427 Mon Sep 17 00:00:00 2001 From: nerte Date: Mon, 24 Feb 2025 20:44:49 +0900 Subject: [PATCH 38/38] =?UTF-8?q?[Fix]=20=EA=B0=9C=EB=B0=9C=20=ED=99=98?= =?UTF-8?q?=EA=B2=BD=20=EC=8B=A4=ED=96=89=EC=8B=9C=20=EC=9D=B4=EB=B2=A4?= =?UTF-8?q?=ED=8A=B8=20=ED=95=B8=EB=93=A4=EB=9F=AC=20=EB=8F=99=EC=9E=91=20?= =?UTF-8?q?=EC=98=A4=EB=A5=98=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/api/comment.api.tsx | 2 +- src/components/Tag/Tag.tsx | 7 ++++++- src/components/common/Input/Input.style.tsx | 1 + src/components/common/Input/Input.tsx | 9 +++++++-- src/components/common/Input/TagInput.tsx | 0 src/pages/AddItem/AddItem.tsx | 1 + 6 files changed, 16 insertions(+), 4 deletions(-) create mode 100644 src/components/common/Input/TagInput.tsx diff --git a/src/api/comment.api.tsx b/src/api/comment.api.tsx index 88859589..a2718b42 100644 --- a/src/api/comment.api.tsx +++ b/src/api/comment.api.tsx @@ -1,7 +1,7 @@ import axios from "axios"; const BASE_URL = "https://panda-market-api.vercel.app"; -export async function getProductComments(productId: Params, limit = 3) { +export async function getProductComments({ productId }: Params, limit = 3) { try { const res = await axios.get( `${BASE_URL}/products/${productId}/comments?limit=${limit}` diff --git a/src/components/Tag/Tag.tsx b/src/components/Tag/Tag.tsx index ca00dbbd..94d6d811 100644 --- a/src/components/Tag/Tag.tsx +++ b/src/components/Tag/Tag.tsx @@ -16,7 +16,12 @@ export default function Tag({ tags, ...props }: Props) { #{tag} {!props.$product && ( - + onClick(tag) : undefined} + {...rest} + /> )} diff --git a/src/components/common/Input/Input.style.tsx b/src/components/common/Input/Input.style.tsx index 193ca0fe..08120c8c 100644 --- a/src/components/common/Input/Input.style.tsx +++ b/src/components/common/Input/Input.style.tsx @@ -5,6 +5,7 @@ export interface StyleProps { $comment?: boolean; $textArea?: boolean; $edit?: boolean; + onKeyUp?: (e: React.KeyboardEvent) => void; } export const InputWrapper = styled.div` width: 100%; diff --git a/src/components/common/Input/Input.tsx b/src/components/common/Input/Input.tsx index 2d019e94..9cc08c0d 100644 --- a/src/components/common/Input/Input.tsx +++ b/src/components/common/Input/Input.tsx @@ -14,7 +14,7 @@ interface Props extends S.StyleProps { tag?: boolean; value?: string; onKeyUp?: (e: React.KeyboardEvent) => void; - type?: "text" | "number" | "password" | "email"; + type?: "text" | "number"; } export function Input({ onChange, type = "text", ...props }: Props) { const { label, onKeyUp, ...rest } = props; @@ -22,7 +22,12 @@ export function Input({ onChange, type = "text", ...props }: Props) { return ( {!label && {label}} - + ); } diff --git a/src/components/common/Input/TagInput.tsx b/src/components/common/Input/TagInput.tsx new file mode 100644 index 00000000..e69de29b diff --git a/src/pages/AddItem/AddItem.tsx b/src/pages/AddItem/AddItem.tsx index 911349d2..a0c2c658 100644 --- a/src/pages/AddItem/AddItem.tsx +++ b/src/pages/AddItem/AddItem.tsx @@ -30,6 +30,7 @@ function AddItem() { }; const CreateTag = (e: React.KeyboardEvent) => { + console.log("createTag 함수 들어옴"); if (e.key === "Enter" && tag.trim() !== "") { const notDuplicate = formData.tags.includes(tag.trim()); if (!notDuplicate) {