diff --git a/index.html b/index.html index df3003494..ad10a3e67 100644 --- a/index.html +++ b/index.html @@ -1,4 +1,4 @@ - + @@ -7,6 +7,6 @@
- + diff --git a/package-lock.json b/package-lock.json index 456249018..d2240f0b8 100644 --- a/package-lock.json +++ b/package-lock.json @@ -17,14 +17,15 @@ }, "devDependencies": { "@eslint/js": "^9.13.0", - "@types/react": "^18.3.12", - "@types/react-dom": "^18.3.1", + "@types/react": "^18.3.18", + "@types/react-dom": "^18.3.5", "@vitejs/plugin-react": "^4.3.3", "eslint": "^9.13.0", "eslint-plugin-react": "^7.37.2", "eslint-plugin-react-hooks": "^5.0.0", "eslint-plugin-react-refresh": "^0.4.14", "globals": "^15.11.0", + "typescript": "^5.7.2", "vite": "^5.4.10" } }, @@ -1317,9 +1318,9 @@ "license": "MIT" }, "node_modules/@types/react": { - "version": "18.3.12", - "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.12.tgz", - "integrity": "sha512-D2wOSq/d6Agt28q7rSI3jhU7G6aiuzljDGZ2hTZHIkrTLUI+AF3WMeKkEZ9nN2fkBAlcktT6vcZjDFiIhMYEQw==", + "version": "18.3.18", + "resolved": "https://registry.npmjs.org/@types/react/-/react-18.3.18.tgz", + "integrity": "sha512-t4yC+vtgnkYjNSKlFx1jkAhH8LgTo2N/7Qvi83kdEaUtMDiwpbLAktKDaAMlRcJ5eSxZkH74eEGt1ky31d7kfQ==", "dev": true, "license": "MIT", "dependencies": { @@ -1328,13 +1329,13 @@ } }, "node_modules/@types/react-dom": { - "version": "18.3.1", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.1.tgz", - "integrity": "sha512-qW1Mfv8taImTthu4KoXgDfLuk4bydU6Q/TkADnDWWHwi4NX4BR+LWfTp2sVmTqRrsHvyDDTelgelxJ+SsejKKQ==", + "version": "18.3.5", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.3.5.tgz", + "integrity": "sha512-P4t6saawp+b/dFrUr2cvkVsfvPguwsxtH6dNIYRllMsefqFzkZk5UIjzyDOv5g1dXIPdG4Sp1yCR4Z6RCUsG/Q==", "dev": true, "license": "MIT", - "dependencies": { - "@types/react": "*" + "peerDependencies": { + "@types/react": "^18.0.0" } }, "node_modules/@types/stylis": { @@ -4387,6 +4388,20 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/typescript": { + "version": "5.7.2", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-5.7.2.tgz", + "integrity": "sha512-i5t66RHxDvVN40HfDd1PsEThGNnlMCMT3jMUuoh9/0TaqWevNontacunWyN02LA9/fIbEWlcHZcgTKb9QoaLfg==", + "dev": true, + "license": "Apache-2.0", + "bin": { + "tsc": "bin/tsc", + "tsserver": "bin/tsserver" + }, + "engines": { + "node": ">=14.17" + } + }, "node_modules/unbox-primitive": { "version": "1.0.2", "resolved": "https://registry.npmjs.org/unbox-primitive/-/unbox-primitive-1.0.2.tgz", diff --git a/package.json b/package.json index 773bc1a39..8c2dad762 100644 --- a/package.json +++ b/package.json @@ -19,14 +19,15 @@ }, "devDependencies": { "@eslint/js": "^9.13.0", - "@types/react": "^18.3.12", - "@types/react-dom": "^18.3.1", + "@types/react": "^18.3.18", + "@types/react-dom": "^18.3.5", "@vitejs/plugin-react": "^4.3.3", "eslint": "^9.13.0", "eslint-plugin-react": "^7.37.2", "eslint-plugin-react-hooks": "^5.0.0", "eslint-plugin-react-refresh": "^0.4.14", "globals": "^15.11.0", + "typescript": "^5.7.2", "vite": "^5.4.10" } } diff --git a/src/App.css b/src/App.css index 656ce7986..2a9784970 100644 --- a/src/App.css +++ b/src/App.css @@ -1,103 +1,415 @@ /* 초기화 */ :root { - --black: #1F2937; - --gray: #F3F4F6; - --main: #3692FF; + --black: #1f2937; + --gray: #f3f4f6; + --main: #3692ff; } -html {overflow-y:scroll;font-size: 10px;} -body {margin:0;padding:0;font-size:1.6rem;background:#fff; color: var(--black);} -body {font-family: "Pretendard Variable", Pretendard, -apple-system, BlinkMacSystemFont, system-ui, Roboto, "Helvetica Neue", "Segoe UI", "Apple SD Gothic Neo", "Noto Sans KR", "Malgun Gothic", "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", sans-serif;} -html, h1, h2, h3, h4, h5, h6, form, fieldset, img {margin:0;padding:0;border:0;font-weight: 400;} -h1, h2, h3, h4, h5, h6 {font-size: 1.6rem; font-family: "Pretendard Variable", Pretendard, -apple-system, BlinkMacSystemFont, system-ui, Roboto, "Helvetica Neue", "Segoe UI", "Apple SD Gothic Neo", "Noto Sans KR", "Malgun Gothic", "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", sans-serif;} -article, aside, details, figcaption, figure, footer, header, hgroup, menu, nav, section {display:block} -ul, dl,dt,dd {margin:0;padding:0;list-style:none} -legend {position:absolute;margin:0;padding:0;font-size:0;line-height:0;text-indent:-9999em;overflow:hidden} -label, input, button, select, img {vertical-align:middle;font-size: 1.6rem;} -input, button {margin:0;padding:0;font-family: "Pretendard Variable", Pretendard, -apple-system, BlinkMacSystemFont, system-ui, Roboto, "Helvetica Neue", "Segoe UI", "Apple SD Gothic Neo", "Noto Sans KR", "Malgun Gothic", "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", sans-serif; font-size: 1.6rem;} -input[type="submit"] {cursor:pointer} -button {cursor:pointer} -textarea, select {font-family: "Pretendard Variable", Pretendard, -apple-system, BlinkMacSystemFont, system-ui, Roboto, "Helvetica Neue", "Segoe UI", "Apple SD Gothic Neo", "Noto Sans KR", "Malgun Gothic", "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", sans-serif; font-size: 1.6rem;} -select {margin:0} -p {margin:0;padding:0;word-break:break-all} -hr {display:none} -pre {overflow-x:scroll;font-size: 1.6rem;} -a {color: var(--black); text-decoration:none} -*, :after, :before { - -webkit-box-sizing:border-box; - -moz-box-sizing:border-box; - box-sizing:border-box; -} -input[type=text],input[type=password], textarea {outline:none;} -input[type=text]:focus,input[type=password]:focus, textarea:focus,select:focus {box-shadow: none;} -img {display: block;} - -.btn_reset {display: block; -webkit-appearance: none; -moz-appearance: none; appearance: none; background: none; border: none; padding: 0; margin: 0; box-shadow: none; font: inherit; color: inherit; cursor: pointer; outline: none; } -.inp_reset {display: block; -webkit-appearance: none; -moz-appearance: none; appearance: none; background: none; border: none; padding: 0; margin: 0; box-shadow: none; font: inherit; color: inherit;} +html { + overflow-y: scroll; + font-size: 10px; +} +body { + margin: 0; + padding: 0; + font-size: 1.6rem; + background: #fff; + color: var(--black); +} +body { + font-family: "Pretendard Variable", Pretendard, -apple-system, BlinkMacSystemFont, system-ui, Roboto, "Helvetica Neue", "Segoe UI", "Apple SD Gothic Neo", "Noto Sans KR", "Malgun Gothic", "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", + sans-serif; +} +html, +h1, +h2, +h3, +h4, +h5, +h6, +form, +fieldset, +img { + margin: 0; + padding: 0; + border: 0; + font-weight: 400; +} +h1, +h2, +h3, +h4, +h5, +h6 { + font-size: 1.6rem; + font-family: "Pretendard Variable", Pretendard, -apple-system, BlinkMacSystemFont, system-ui, Roboto, "Helvetica Neue", "Segoe UI", "Apple SD Gothic Neo", "Noto Sans KR", "Malgun Gothic", "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", + sans-serif; +} +article, +aside, +details, +figcaption, +figure, +footer, +header, +hgroup, +menu, +nav, +section { + display: block; +} +ul, +dl, +dt, +dd { + margin: 0; + padding: 0; + list-style: none; +} +legend { + position: absolute; + margin: 0; + padding: 0; + font-size: 0; + line-height: 0; + text-indent: -9999em; + overflow: hidden; +} +label, +input, +button, +select, +img { + vertical-align: middle; + font-size: 1.6rem; +} +input, +button { + margin: 0; + padding: 0; + font-family: "Pretendard Variable", Pretendard, -apple-system, BlinkMacSystemFont, system-ui, Roboto, "Helvetica Neue", "Segoe UI", "Apple SD Gothic Neo", "Noto Sans KR", "Malgun Gothic", "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", + sans-serif; + font-size: 1.6rem; +} +input[type="submit"] { + cursor: pointer; +} +button { + cursor: pointer; +} +textarea, +select { + font-family: "Pretendard Variable", Pretendard, -apple-system, BlinkMacSystemFont, system-ui, Roboto, "Helvetica Neue", "Segoe UI", "Apple SD Gothic Neo", "Noto Sans KR", "Malgun Gothic", "Apple Color Emoji", "Segoe UI Emoji", "Segoe UI Symbol", + sans-serif; + font-size: 1.6rem; +} +select { + margin: 0; +} +p { + margin: 0; + padding: 0; + word-break: break-all; +} +hr { + display: none; +} +pre { + overflow-x: scroll; + font-size: 1.6rem; +} +a { + color: var(--black); + text-decoration: none; +} +*, +:after, +:before { + -webkit-box-sizing: border-box; + -moz-box-sizing: border-box; + box-sizing: border-box; +} +input[type="text"], +input[type="password"], +textarea { + outline: none; +} +input[type="text"]:focus, +input[type="password"]:focus, +textarea:focus, +select:focus { + box-shadow: none; +} +img { + display: block; +} -.btn_blue {display: block; -webkit-appearance: none; -moz-appearance: none; appearance: none; background: none; border: none; padding: 0; margin: 0; box-shadow: none; font: inherit; color: inherit; cursor: pointer; outline: none;} -.btn_blue {min-width: 88px; height: 42px; padding: 0 23px; background-color: var(--main); border-radius: 12px; color: #F3F4F6; text-align: center; font-size: 1.6rem; font-weight: 600; line-height: 42px; transition: all 0.2s;} -.btn_blue:hover {background-color: #1967D6;} -.btn_blue:active {background-color: #1251AA;} -.btn_blue:disabled {background-color: #9CA3AF; cursor: not-allowed;} +.btn_reset { + display: block; + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; + background: none; + border: none; + padding: 0; + margin: 0; + box-shadow: none; + font: inherit; + color: inherit; + cursor: pointer; + outline: none; +} +.inp_reset { + display: block; + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; + background: none; + border: none; + padding: 0; + margin: 0; + box-shadow: none; + font: inherit; + color: inherit; +} -.btn_blue.sml {min-width: 74px; border-radius: 8px; font-weight: 400;} -.btn_blue.lg {min-width: 240px; height: 48px; line-height: 48px; border-radius: 80px; font-size: 1.8rem; font-weight: 600;} +.btn_blue { + display: block; + -webkit-appearance: none; + -moz-appearance: none; + appearance: none; + background: none; + border: none; + padding: 0; + margin: 0; + box-shadow: none; + font: inherit; + color: inherit; + cursor: pointer; + outline: none; +} +.btn_blue { + min-width: 88px; + height: 42px; + padding: 0 23px; + background-color: var(--main); + border-radius: 12px; + color: #f3f4f6; + text-align: center; + font-size: 1.6rem; + font-weight: 600; + line-height: 42px; + transition: all 0.2s; +} +.btn_blue:hover { + background-color: #1967d6; +} +.btn_blue:active { + background-color: #1251aa; +} +.btn_blue:disabled { + background-color: #9ca3af; + cursor: not-allowed; +} -.select_common {position: relative; z-index: 2;} -.select_common > p {position: relative; z-index: 3; min-width: 130px; height: 42px; padding-left: 20px; padding-right: 50px; border: 1px solid #E5E7EB; background-color: #fff; border-radius: 12px; font-size: 1.6rem; font-weight: 400; line-height: 42px; cursor: pointer;} -.select_common > p::after {content: ''; position: absolute; right: 20px; top: 50%; transform: translateY(-50%); width: 24px; height: 24px; background: url('./../src/assets/select_arrow.svg') no-repeat 50% 50% / cover; transition: all 0.2s;} -.select_common > .select_list {visibility: hidden; opacity: 0; position: absolute; top: 0%; left: 0; z-index: 2; width: 100%; padding-top: 8px; transition: all 0.2s;} -.select_common > .select_list > ul {overflow: hidden; border: 1px solid #E5E7EB; border-radius: 12px; } -.select_common > .select_list > ul > li {display : flex; align-items: center; justify-content: center; height: 42px; background-color: #fff; font-size: 1.6rem; line-height: 1; cursor: pointer; transition: all 0.2s;} -.select_common > .select_list > ul > li + li {border-top: 1px solid #E5E7EB;} -.select_common > .select_list > ul > li:hover {background-color: var(--gray);} -.select_common:hover > p::after {transform: translateY(-50%) rotate(180deg);} -.select_common:hover .select_list {visibility: visible; opacity: 1; top: 100%;} +.btn_blue.sml { + min-width: 74px; + border-radius: 8px; + font-weight: 400; +} +.btn_blue.lg { + min-width: 240px; + height: 48px; + line-height: 48px; + border-radius: 80px; + font-size: 1.8rem; + font-weight: 600; +} -.select_common.active > p::after {transform: translateY(-50%) rotate(180deg) !important;} -.select_common.active .select_list {visibility: visible !important; opacity: 1 !important; top: 100% !important;} +.select_common { + position: relative; + z-index: 2; +} +.select_common > p { + position: relative; + z-index: 3; + min-width: 130px; + height: 42px; + padding-left: 20px; + padding-right: 50px; + border: 1px solid #e5e7eb; + background-color: #fff; + border-radius: 12px; + font-size: 1.6rem; + font-weight: 400; + line-height: 42px; + cursor: pointer; +} +.select_common > p::after { + content: ""; + position: absolute; + right: 20px; + top: 50%; + transform: translateY(-50%); + width: 24px; + height: 24px; + background: url("./../src/assets/select_arrow.svg") no-repeat 50% 50% / cover; + transition: all 0.2s; +} +.select_common > .select_list { + visibility: hidden; + opacity: 0; + position: absolute; + top: 0%; + left: 0; + z-index: 2; + width: 100%; + padding-top: 8px; + transition: all 0.2s; +} +.select_common > .select_list > ul { + overflow: hidden; + border: 1px solid #e5e7eb; + border-radius: 12px; +} +.select_common > .select_list > ul > li { + display: flex; + align-items: center; + justify-content: center; + height: 42px; + background-color: #fff; + font-size: 1.6rem; + line-height: 1; + cursor: pointer; + transition: all 0.2s; +} +.select_common > .select_list > ul > li + li { + border-top: 1px solid #e5e7eb; +} +.select_common > .select_list > ul > li:hover { + background-color: var(--gray); +} +.select_common.active > p::after { + transform: translateY(-50%) rotate(180deg) !important; +} +.select_common.active .select_list { + visibility: visible !important; + opacity: 1 !important; + top: 100% !important; +} /* 레이아웃 */ -#root {padding-top: 70px;} -.inner {max-width: 1200px; width: 100%; margin: 0 auto;} -.main {padding: 24px 0 150px;} -.item_list_wrap + .item_list_wrap {margin-top: 40px;} -.blank {display : flex; align-items: center; justify-content: center; font-size: 20px; width: 100%; height: 500px; border: 1px solid #DFDFDF;} +#root { + padding-top: 70px; +} +.inner { + max-width: 1200px; + width: 100%; + margin: 0 auto; +} +.main { + padding: 24px 0 150px; +} +.item_list_wrap + .item_list_wrap { + margin-top: 40px; +} +.blank { + display: flex; + align-items: center; + justify-content: center; + font-size: 20px; + width: 100%; + height: 500px; + border: 1px solid #dfdfdf; +} /* 서브타이틀 */ -.tit_box {display : flex; align-items: center; margin-bottom: 24px;} -.tit_box .subtitle {color: #111827; font-size: 2.0rem; font-weight: 700; line-height: 1.6;} +.tit_box { + display: flex; + align-items: center; + margin-bottom: 24px; +} +.tit_box .subtitle { + color: #111827; + font-size: 2rem; + font-weight: 700; + line-height: 1.6; +} /* 상품박스 레이아웃 */ -.product_list {display: flex; flex-wrap: wrap; margin: 0 -12px -40px;} -.product_list > li {width: 100%; margin-bottom: 40px; padding: 0 12px;} -.product_list.col2 > li {width: 50%;} -.product_list.col3 > li {width: 33.3333%;} -.product_list.col4 > li {width: 25%;} -.product_list.col5 > li {width: 20%;} +.product_list { + display: flex; + flex-wrap: wrap; + margin: 0 -12px -40px; +} +.product_list > li { + width: 100%; + margin-bottom: 40px; + padding: 0 12px; +} +.product_list.col2 > li { + width: 50%; +} +.product_list.col3 > li { + width: 33.3333%; +} +.product_list.col4 > li { + width: 25%; +} +.product_list.col5 > li { + width: 20%; +} @media (max-width: 1200px) { - .select_common:hover > p::after {transform: translateY(-50%) rotate(0);} - .select_common:hover .select_list {visibility: hidden; opacity: 0; top: 0%;} - - .inner {padding-left: 24px; padding-right: 24px;} - .main {padding-bottom: 72px;} + .inner { + padding-left: 24px; + padding-right: 24px; + } + .main { + padding-bottom: 72px; + } /* 상품박스 레이아웃 */ - .product_list {margin: 0 -8px -40px;} - .product_list > li {padding: 0 8px;} + .product_list { + margin: 0 -8px -40px; + } + .product_list > li { + padding: 0 8px; + } - .product_list.col2 {margin: 0 -5px -40px;} - .product_list.col2 > li {padding: 0 5px;} + .product_list.col2 { + margin: 0 -5px -40px; + } + .product_list.col2 > li { + padding: 0 5px; + } } @media (max-width: 768px) { - .inner {padding-left: 16px; padding-right: 16px;} + .inner { + padding-left: 16px; + padding-right: 16px; + } - .select_common > p {display : flex; align-items: center; justify-content: center; min-width: 42px; width: 42px; height: 42px; margin: 0; padding: 0;} - .select_common > p::after {display: none;} + .select_common > p { + display: flex; + align-items: center; + justify-content: center; + min-width: 42px; + width: 42px; + height: 42px; + margin: 0; + padding: 0; + } + .select_common > p::after { + display: none; + } - .select_common > .select_list {left: auto; right: 0; width: 130px; padding-top: 4px;} + .select_common > .select_list { + left: auto; + right: 0; + width: 130px; + padding-top: 4px; + } } diff --git a/src/App.js b/src/App.js deleted file mode 100644 index 378457572..000000000 --- a/src/App.js +++ /dev/null @@ -1,25 +0,0 @@ -import logo from './logo.svg'; -import './App.css'; - -function App() { - return ( -
-
- logo -

- Edit src/App.js and save to reload. -

- - Learn React - -
-
- ); -} - -export default App; diff --git a/src/App.test.js b/src/App.test.js deleted file mode 100644 index 1f03afeec..000000000 --- a/src/App.test.js +++ /dev/null @@ -1,8 +0,0 @@ -import { render, screen } from '@testing-library/react'; -import App from './App'; - -test('renders learn react link', () => { - render(); - const linkElement = screen.getByText(/learn react/i); - expect(linkElement).toBeInTheDocument(); -}); diff --git a/src/App.jsx b/src/App.tsx similarity index 86% rename from src/App.jsx rename to src/App.tsx index 1cbe3a766..d8f3687a6 100644 --- a/src/App.jsx +++ b/src/App.tsx @@ -2,7 +2,7 @@ import { BrowserRouter, Route, Routes } from "react-router-dom"; import "./App.css"; import Header from "./components/Header"; import MainPage from "./page/MainPage"; -import ItemsPage from "./page/ItemsPage"; +import ProductListPage from "./page/ProductListPage"; import AddItemPage from "./page/AddItemPage"; import FreeBoardPage from "./page/FreeBoardPage"; import ProductDetailPage from "./page/ProductDetailPage"; @@ -13,7 +13,7 @@ function App() {
} /> - } /> + } /> } /> } /> } /> diff --git a/src/assets/comment_empty.png b/src/assets/comment_empty.png new file mode 100644 index 000000000..25019b5af Binary files /dev/null and b/src/assets/comment_empty.png differ diff --git a/src/components/AllProduct.css b/src/components/AllProduct.css index 13c0a14ca..b17869474 100644 --- a/src/components/AllProduct.css +++ b/src/components/AllProduct.css @@ -1,16 +1,62 @@ -.product_search {position: relative; height: 42px; margin-left: auto; padding-left: 44px; padding-right: 20px; background-color: #F3F4F6; border-radius: 12px; } -.product_search::after {content: ''; position: absolute; left: 16px; top: 50%; transform: translateY(-50%); width: 24px; height: 24px; background: url('./../assets/icon_search.svg') no-repeat 50% 50% / cover;} -.product_search > input {width: 100%; height: 100%; font-size: 1.6rem; font-weight: 400; line-height: 1;} -.product_search > input::placeholder {color: #9CA3AF;} +.product_search { + position: relative; + width: 325px; + height: 42px; + margin-left: auto; + padding-left: 44px; + padding-right: 20px; + background-color: #f3f4f6; + border-radius: 12px; +} +.product_search::after { + content: ""; + position: absolute; + left: 16px; + top: 50%; + transform: translateY(-50%); + width: 24px; + height: 24px; + background: url("./../assets/icon_search.svg") no-repeat 50% 50% / cover; +} +.product_search > input { + width: 100%; + height: 100%; + font-size: 1.6rem; + font-weight: 400; + line-height: 1; +} +.product_search > input::placeholder { + color: #9ca3af; +} -.product_add_btn {margin-left: 12px;} +.product_add_btn { + margin-left: 12px; +} -.product_sort {margin-left: 12px;} +.product_sort { + margin-left: 12px; +} @media (max-width: 768px) { - .item_list_wrap .tit_box {flex-wrap: wrap; gap: 8px 0; margin-bottom: 16px;} - .item_list_wrap .tit_box .subtitle {order:1;} - .item_list_wrap .tit_box .product_add_btn {order:2; margin-left: auto;} - .item_list_wrap .tit_box .product_search {order:3; width: calc(100% - 50px); margin-left: 0;} - .item_list_wrap .tit_box .product_sort {order: 4; margin-left: auto;} + .item_list_wrap .tit_box { + flex-wrap: wrap; + gap: 8px 0; + margin-bottom: 16px; + } + .item_list_wrap .tit_box .subtitle { + order: 1; + } + .item_list_wrap .tit_box .product_add_btn { + order: 2; + margin-left: auto; + } + .item_list_wrap .tit_box .product_search { + order: 3; + width: calc(100% - 50px); + margin-left: 0; + } + .item_list_wrap .tit_box .product_sort { + order: 4; + margin-left: auto; + } } diff --git a/src/components/AllProduct.jsx b/src/components/AllProduct.jsx deleted file mode 100644 index 2d3feab99..000000000 --- a/src/components/AllProduct.jsx +++ /dev/null @@ -1,104 +0,0 @@ -import { useMediaQuery } from "react-responsive"; -import getProduct from './api.jsx'; -import Paging from './Paging.jsx'; -import ProductItem from './ProductItem.jsx'; -import { useState, useEffect } from 'react'; -import SubTitle from './SubTitle.jsx'; -import './AllProduct.css' -import selectIcon from "./../assets/icon_select.svg"; -import { Link } from 'react-router-dom'; - -const AllProduct = ({col}) => { - - const isTablet = useMediaQuery({ - query: "(max-width: 1200px)", - }); - const isMobile = useMediaQuery({ - query: "(max-width: 768px)", - }); - - const [items, setItems] = useState([]); - const [order, setOrder] = useState('recent'); - const [keyword, setKeyword] = useState(''); - const [orderName, setOrderName] = useState('최신순'); - const [pageSize, setPageSize] = useState(isMobile ? 4 : isTablet ? 6 : 10); - // 페이지네이션 관련 상태 추가 - const [currentPage, setCurrentPage] = useState(1); // 현재 페이지 번호 - const [totalItems, setTotalItems] = useState(0); // 전체 아이템 수 - - useEffect(() => { - setPageSize(isMobile ? 4 : isTablet ? 6 : 10); - setCurrentPage(1); - }, [isMobile, isTablet]); - - const handleLoad = async (orderQuery, pageSizeQuery, keywordQuery, pageQuery) => { - const { list, totalCount } = await getProduct({order: orderQuery, pageSize: pageSizeQuery, keyword: keywordQuery, page: pageQuery}); - setItems(list); - setTotalItems(totalCount); - }; - - useEffect(() => { - handleLoad(order, pageSize, keyword, currentPage); - }, [order, pageSize, keyword, currentPage]); - - const handleOrderChange = (newOrder, newOrderName) => { - setOrder(newOrder); - setOrderName(newOrderName); - setCurrentPage(1); - } - - const handleKeywordChange = (e) => { - setKeyword(e.target.value); - setCurrentPage(1); - } - - const handleSelect = (e) => { - e.stopPropagation(); - e.currentTarget.classList.toggle('active'); - } - - return( - <> -

- -
- -
-
- 상품 등록하기 -
-
-
- -

{isMobile ? 상품정렬 : orderName }

-
-
    -
  • handleOrderChange('recent', '최신순')}>최신순
  • -
  • handleOrderChange('favorite', '좋아요순')}>좋아요순
  • -
-
-
-
-

-
-
    - {items.map((item) => { - return ( -
  • - -
  • - ); - })} -
-
- setCurrentPage(page)} - /> - - ) -} - -export default AllProduct; diff --git a/src/components/AllProduct.tsx b/src/components/AllProduct.tsx new file mode 100644 index 000000000..65600736b --- /dev/null +++ b/src/components/AllProduct.tsx @@ -0,0 +1,118 @@ +import { useMediaQuery } from "react-responsive"; +import getProduct from "./api"; +import Paging from "./Paging"; +import ProductItem from "./ProductItem"; +import { useRef, useState, useEffect } from "react"; +import SubTitle from "./SubTitle"; +import "./AllProduct.css"; +import selectIcon from "./../assets/icon_select.svg"; +import { Link } from "react-router-dom"; +import useOutSideClick from "../hooks/useOutSideClick"; +import Product from "../types/Product"; +import { OrderQuery, OrderKorQuery } from "../types/Query"; + +interface Props { + col: number; +} + +type PageSizeQuery = number; +type KeywordQuery = string; +type PageQuery = number; + +const AllProduct = ({ col }: Props) => { + const isTablet = useMediaQuery({ + query: "(max-width: 1200px)", + }); + const isMobile = useMediaQuery({ + query: "(max-width: 768px)", + }); + + const [items, setItems] = useState([]); + const [order, setOrder] = useState("recent"); + const [keyword, setKeyword] = useState(""); + const [orderName, setOrderName] = useState("최신순"); + const [pageSize, setPageSize] = useState(isMobile ? 4 : isTablet ? 6 : 10); + // 페이지네이션 관련 상태 추가 + const [currentPage, setCurrentPage] = useState(1); // 현재 페이지 번호 + const [totalItems, setTotalItems] = useState(0); // 전체 아이템 수 + + useEffect(() => { + setPageSize(isMobile ? 4 : isTablet ? 6 : 10); + setCurrentPage(1); + }, [isMobile, isTablet]); + + const handleLoad = async (orderQuery: OrderQuery, pageSizeQuery: PageSizeQuery, keywordQuery: KeywordQuery, pageQuery: PageQuery): Promise => { + const { list, totalCount } = await getProduct({ order: orderQuery, pageSize: pageSizeQuery, keyword: keywordQuery, page: pageQuery }); + setItems(list); + setTotalItems(totalCount); + }; + + useEffect(() => { + handleLoad(order, pageSize, keyword, currentPage); + }, [order, pageSize, keyword, currentPage]); + + const handleOrderChange = (newOrder: OrderQuery, newOrderName: OrderKorQuery) => { + setOrder(newOrder); + setOrderName(newOrderName); + setCurrentPage(1); + }; + + const handleKeywordChange = (e: React.ChangeEvent) => { + setKeyword(e.target.value); + setCurrentPage(1); + }; + + const selectRef = useRef(null); + + useOutSideClick(selectRef, () => { + if (selectRef.current) { + selectRef.current?.classList.remove("active"); + } + }); + + const handleSelect = (e: React.MouseEvent) => { + e.stopPropagation(); + e.currentTarget.classList.toggle("active"); + }; + + return ( + <> +

+ +
+ +
+
+ + 상품 등록하기 + +
+
+
+

{isMobile ? 상품정렬 : orderName}

+
+
    +
  • handleOrderChange("recent", "최신순")}>최신순
  • +
  • handleOrderChange("favorite", "좋아요순")}>좋아요순
  • +
+
+
+
+

+
+
    + {items.map((item) => { + return ( +
  • + +
  • + ); + })} +
+
+ setCurrentPage(page)} /> + + ); +}; + +export default AllProduct; diff --git a/src/components/BestProduct.tsx b/src/components/BestProduct.tsx new file mode 100644 index 000000000..7b3c392f9 --- /dev/null +++ b/src/components/BestProduct.tsx @@ -0,0 +1,60 @@ +import { useMediaQuery } from "react-responsive"; +import getProduct from "./api"; +import ProductItem from "./ProductItem"; +import { useState, useEffect } from "react"; +import SubTitle from "./SubTitle"; +import Product from "../types/Product"; +import { OrderQuery } from "../types/Query"; + +interface Props { + col: number; +} + +type PageSizeQuery = number; + +const BestProduct = ({ col }: Props) => { + const isTablet = useMediaQuery({ + query: "(max-width: 1200px)", + }); + const isMobile = useMediaQuery({ + query: "(max-width: 768px)", + }); + + const [items, setItems] = useState([]); + const [order, setOrder] = useState("favorite"); + const [pageSize, setPageSize] = useState(isMobile ? 1 : isTablet ? 2 : 4); + + useEffect(() => { + setPageSize(isMobile ? 1 : isTablet ? 2 : 4); + }, [isMobile, isTablet]); + + const handleLoad = async (orderQuery: OrderQuery, pageSizeQuery: PageSizeQuery): Promise => { + const { list } = await getProduct({ order: orderQuery, pageSize: pageSizeQuery }); + setItems(list); + }; + + useEffect(() => { + handleLoad(order, pageSize); + }, [order, pageSize]); + + return ( + <> +

+ +

+
+
    + {items.map((item) => { + return ( +
  • + +
  • + ); + })} +
+
+ + ); +}; + +export default BestProduct; diff --git a/src/components/BsetProduct.jsx b/src/components/BsetProduct.jsx deleted file mode 100644 index 312a71fae..000000000 --- a/src/components/BsetProduct.jsx +++ /dev/null @@ -1,53 +0,0 @@ -import { useMediaQuery } from "react-responsive"; -import getProduct from './api.jsx'; -import ProductItem from './ProductItem.jsx'; -import { useState, useEffect } from 'react'; -import SubTitle from './SubTitle.jsx'; - -const BsetProduct = ({col}) => { - - const isTablet = useMediaQuery({ - query: "(max-width: 1200px)", - }); - const isMobile = useMediaQuery({ - query: "(max-width: 768px)", - }); - - const [items, setItems] = useState([]); - const [order, setOrder] = useState('favorite'); - const [pageSize, setPageSize] = useState(isMobile ? 1 : isTablet ? 2 : 4); - - useEffect(() => { - setPageSize(isMobile ? 1 : isTablet ? 2 : 4); - }, [isMobile, isTablet]); - - const handleLoad = async (orderQuery, pageSizeQuery) => { - const { list } = await getProduct({order: orderQuery, pageSize: pageSizeQuery}); - setItems(list); - }; - - useEffect(() => { - handleLoad(order, pageSize); - }, [order, pageSize]); - - return( - <> -

- -

-
-
    - {items.map((item) => { - return ( -
  • - -
  • - ); - })} -
-
- - ) -} - -export default BsetProduct; diff --git a/src/components/DetailBtm.css b/src/components/DetailBtm.css index e69de29bb..81aab0c5b 100644 --- a/src/components/DetailBtm.css +++ b/src/components/DetailBtm.css @@ -0,0 +1,100 @@ +.product_detail_comment { + margin-top: 40px; + padding-top: 40px; + border-top: 1px solid #e5e7eb; +} +.product_detail_comment .comment_top .tit { + margin-bottom: 9px; + font-size: 1.6rem; + font-weight: 600; + line-height: 1.625; +} +.product_detail_comment .comment_top .textarea_box { + margin-bottom: 16px; +} +.product_detail_comment .comment_top .textarea_box textarea { + width: 100%; + min-height: 104px; + padding: 16px 24px; + border-radius: 12px; + background-color: #f3f4f6; + resize: none; +} +.product_detail_comment .comment_top .textarea_box textarea::placeholder { + color: #9ca3af; +} +.product_detail_comment .comment_top > button { + margin-left: auto; +} +.product_detail_comment .comment_list { + margin-top: 24px; +} +.product_detail_comment .comment_list > li { + position: relative; + padding-bottom: 12px; + padding-right: 40px; + border-bottom: 1px solid #e5e7eb; + word-break: keep-all; +} +.product_detail_comment .comment_list > li + li { + margin-top: 24px; +} +.product_detail_comment .comment_list > li .comment_menu { + position: absolute; + top: 0; + right: 0; +} +.product_detail_comment .comment_list > li .comment_menu > button { + display: flex; + align-items: center; + justify-content: center; + width: 24px; + height: 24px; + border-radius: 4px; + transition: all 0.2s; +} +.product_detail_comment .comment_list > li .comment_menu > button:hover { + background: #f3f4f6; +} +.product_detail_comment .comment_list > li .comment_menu > ul { + position: absolute; + top: calc(100% + 10px); + right: 0; + border: 1px solid #d1d5db; + border-radius: 8px; + background-color: #fff; + overflow: hidden; +} +.product_detail_comment .comment_list > li .comment_menu > ul > li { +} +.product_detail_comment .comment_list > li .comment_menu > ul > li > button { + width: 140px; + height: 46px; + text-align: center; + color: #6b7280; + font-size: 1.6rem; + transition: all 0.2s; +} +.product_detail_comment .comment_list > li .comment_menu > ul > li > button:hover { + background: #f3f4f6; +} +.product_detail_comment .comment_list > li .text_area { + margin-bottom: 24px; + font-size: 1.4rem; + font-weight: 400; + line-height: 1.7142; +} +.comment_empty { + text-align: center; +} +.comment_empty .thum { + display: flex; + justify-content: center; +} +.comment_empty p { + margin-top: 8px; + font-size: 1.6rem; + color: #9ca3af; + font-weight: 400; + line-height: 1.625; +} diff --git a/src/components/DetailBtm.jsx b/src/components/DetailBtm.jsx deleted file mode 100644 index 2075162d2..000000000 --- a/src/components/DetailBtm.jsx +++ /dev/null @@ -1,78 +0,0 @@ -import menuIcon from "./../assets/menu_dot.svg"; -import React, { useState } from "react"; -import useApi from "./../hooks/useApi"; -import ProfileBox from "./ProfileBox"; - -const DetailBtm = ({ id }) => { - const [commentMenu, setCommentMenu] = useState(null); - const [textValue, setTextValue] = useState(""); - - const handleTextChange = (e) => { - setTextValue(e.target.value); - }; - - const handleCommentMenu = (id) => { - setCommentMenu(commentMenu === id ? null : id); - }; - - const { data, loading, error } = useApi(`https://panda-market-api.vercel.app/products/${id}/comments?limit=10`); - - if (loading) { - return
Loading...
; - } - - if (error) { - return
Error: {error.message}
; - } - - return ( -
-
-
문의하기
-
- -
- -
-
    - {data.list.map((el) => { - return ( -
  • -
    - - {commentMenu === el.id && ( -
      -
    • - -
    • -
    • - -
    • -
    - )} -
    -
    {el.content}
    - -
  • - ); - })} -
-
- ); -}; - -export default DetailBtm; diff --git a/src/components/DetailBtm.tsx b/src/components/DetailBtm.tsx new file mode 100644 index 000000000..2c50d339c --- /dev/null +++ b/src/components/DetailBtm.tsx @@ -0,0 +1,99 @@ +import "./DetailBtm.css"; +import menuIcon from "./../assets/menu_dot.svg"; +import React, { useRef, useState } from "react"; +import useApi from "./../hooks/useApi"; +import ProfileBox from "./ProfileBox"; +import CommentEmpty from "./../assets/comment_empty.png"; +import useOutSideClick from "../hooks/useOutSideClick"; +import Comment from "../types/Comment"; + +interface Props { + id?: string; +} + +const DetailBtm = ({ id }: Props) => { + const [commentMenu, setCommentMenu] = useState(null); + const [textValue, setTextValue] = useState(""); + + const handleTextChange = (e: React.ChangeEvent) => { + setTextValue(e.target.value); + }; + + const handleCommentMenu = (id: Props) => { + setCommentMenu((prev) => (prev === id ? null : id)); + }; + + const menuRef = useRef(null); + useOutSideClick(menuRef, () => setCommentMenu(null)); + + const { data, loading, error } = useApi(`${id}/comments?limit=10`); + + if (loading) { + return
Loading...
; + } + + if (error) { + return
Error: {error.message}
; + } + + return ( +
+
+
문의하기
+
+ +
+ +
+
    + {data?.list?.length === 0 ? ( +
    +
    + 아직 문의가 없어요 이미지 +
    +

    아직 문의가 없어요

    +
    + ) : ( + data?.list.map((el) => { + return ( +
  • +
    + + {commentMenu === el.id && ( +
      +
    • + +
    • +
    • + +
    • +
    + )} +
    +
    {el.content}
    + +
  • + ); + }) + )} +
+
+ ); +}; + +export default DetailBtm; diff --git a/src/components/DetailTop.css b/src/components/DetailTop.css index e69de29bb..021f778a1 100644 --- a/src/components/DetailTop.css +++ b/src/components/DetailTop.css @@ -0,0 +1,105 @@ +.product_detail_item { + display: flex; +} +.product_detail_item .thum { + overflow: hidden; + width: 486px; + height: 486px; + border-radius: 25px; +} +.product_detail_item .thum img { + width: 100%; + height: 100%; + object-fit: cover; +} +.product_detail_item .content { + display: flex; + flex-direction: column; + width: calc(100% - 510px); + margin-left: 24px; +} +.product_detail_item .content .tit { + margin-bottom: 16px; + font-size: 2.4rem; + font-weight: 600; + line-height: 1.3333; +} +.product_detail_item .content .price { + padding-bottom: 16px; + margin-bottom: 24px; + border-bottom: 1px solid #e5e7eb; + font-size: 4rem; + font-weight: 600; +} +.product_detail_item .content .info { +} +.product_detail_item .content .info + .info { + margin-top: 24px; +} +.product_detail_item .content .info > p { + margin-bottom: 16px; + font-size: 1.6rem; + font-weight: 600; + line-height: 1.625; +} +.product_detail_item .content .info > .desc { + color: #4b5563; + font-size: 1.6rem; + line-height: 1.625; +} +.product_detail_item .content .info > .tag { + display: flex; + flex-wrap: wrap; + gap: 8px; +} +.product_detail_item .content .info > .tag > li { + padding: 6px 16px; + background-color: #f3f4f6; + border-radius: 50px; + font-size: 1.6rem; + font-weight: 400; + line-height: 1.625; + transition: all 0.2s; + cursor: pointer; +} +.product_detail_item .content .info > .tag > li:hover { + box-shadow: 2px 2px 5px rgba(0, 0, 0, 0.15); +} +.product_detail_item .content .profile_box { + display: flex; + align-items: center; + margin-top: auto; +} +.product_detail_item .content .profile_box .wish_area { + position: relative; + margin-left: auto; + display: flex; + align-items: center; + padding: 4px 12px; + border: 1px solid #e5e7eb; + border-radius: 35px; + transition: all 0.2s; +} +.product_detail_item .content .profile_box .wish_area:hover { + box-shadow: 2px 2px 5px rgba(0, 0, 0, 0.15); +} +.product_detail_item .content .profile_box .wish_area::before { + content: ""; + width: 1px; + height: 34px; + background-color: #e5e7eb; + position: absolute; + left: -24px; + top: 50%; + transform: translateY(-50%); +} +.product_detail_item .content .profile_box .wish_area .icon img { + height: 24px; +} +.product_detail_item .content .profile_box .wish_area .numb { + margin-left: 4px; + color: #6b7280; + font-size: 1.6rem; + font-weight: 500; + line-height: 1.625; +} diff --git a/src/components/DetailTop.jsx b/src/components/DetailTop.tsx similarity index 75% rename from src/components/DetailTop.jsx rename to src/components/DetailTop.tsx index 4abb94f2e..b92abc03e 100644 --- a/src/components/DetailTop.jsx +++ b/src/components/DetailTop.tsx @@ -1,10 +1,20 @@ +import "./DetailTop.css"; import productImg from "./../assets/item.png"; import wishIcon from "./../assets/icon_wish.svg"; import useApi from "./../hooks/useApi"; import ProfileBox from "./ProfileBox"; +import Product from "../types/Product"; -const DetailTop = ({ id }) => { - const { data, loading, error } = useApi(`https://panda-market-api.vercel.app/products/${id}`); +interface ProductDetail extends Product { + isFavorite: boolean; +} + +interface Props { + id?: string; +} + +const DetailTop = ({ id }: Props) => { + const { data, loading, error } = useApi(`${id}`); if (loading) { return
Loading...
; @@ -21,7 +31,7 @@ const DetailTop = ({ id }) => { return (
- {data.name} (e.target.src = productImg)} /> + {data.name} ((e.target as HTMLImageElement).src = productImg)} />
{data.name}
@@ -43,7 +53,7 @@ const DetailTop = ({ id }) => { diff --git a/src/components/FileInput.css b/src/components/FileInput.css index 4e6e89c25..a879e3f15 100644 --- a/src/components/FileInput.css +++ b/src/components/FileInput.css @@ -1,31 +1,124 @@ -.add_form_list > li .input_file_box {display : flex;} -.add_form_list > li .input_file_box label {display : flex; align-items: center; justify-content: center; flex-direction: column; width: 282px; height: 282px; background-color: #F3F4F6; border-radius: 12px; cursor: pointer;} -.add_form_list > li .input_file_box label > span {margin-top: 12px; color: #9CA3AF; font-size: 1.6rem; font-weight: 400; line-height: 1.625; } -.add_form_list > li .input_file_box input {display: none;} -.add_form_list > li .input_file_box .file_img_list > li {position: relative; overflow: hidden; width: 282px; height: 282px; margin-left: 24px; border-radius: 12px;} -.add_form_list > li .input_file_box .file_img_list > li > .remove_btn {position: absolute; top: 12px; right: 12px; z-index: 2;} -.add_form_list > li .input_file_box .file_img_list > li > img {width: 100%; height: 100%; object-fit: cover;} +.add_form_list > li .input_file_box { + display: flex; +} +.add_form_list > li .input_file_box label { + display: flex; + align-items: center; + justify-content: center; + flex-direction: column; + width: 282px; + height: 282px; + background-color: #f3f4f6; + border-radius: 12px; + cursor: pointer; +} +.add_form_list > li .input_file_box label > span { + margin-top: 12px; + color: #9ca3af; + font-size: 1.6rem; + font-weight: 400; + line-height: 1.625; +} +.add_form_list > li .input_file_box input { + display: none; +} +.add_form_list > li .input_file_box .file_img_list > li { + position: relative; + overflow: hidden; + width: 282px; + height: 282px; + margin-left: 24px; + border-radius: 12px; +} +.add_form_list > li .input_file_box .file_img_list > li > .remove_btn { + position: absolute; + top: 12px; + right: 12px; + z-index: 2; +} +.add_form_list > li .input_file_box .file_img_list > li > img { + width: 100%; + height: 100%; + object-fit: cover; +} -.limit_text {position: relative; z-index: -1; margin-top: -26px; color: #F74747; font-size: 1.6rem; line-height: 1.625; opacity: 0; transition: all 0.2s ease-in-out;} -.limit_text.active {opacity: 1; margin-top: 16px; margin-bottom: -8px;} +.limit_text { + position: relative; + z-index: -1; + margin-top: -26px; + color: #f74747; + font-size: 1.6rem; + line-height: 1.625; + opacity: 0; + transition: all 0.2s ease-in-out; +} +.limit_text.active { + opacity: 1; + margin-top: 16px; + margin-bottom: -8px; +} @media (max-width: 1200px) { - .add_form_list > li .input_file_box label {width: 168px; height: 168px;} - .add_form_list > li .input_file_box .file_img_list > li {width: 168px; height: 168px; margin-left: 10px;} - .limit_text {width: 168px; white-space: nowrap; font-size: 1.4rem;} + .add_form_list > li .input_file_box label { + width: 168px; + height: 168px; + } + .add_form_list > li .input_file_box .file_img_list > li { + width: 168px; + height: 168px; + margin-left: 10px; + } + .limit_text { + width: 168px; + white-space: nowrap; + font-size: 1.4rem; + } } @media (max-width: 768px) { - .add_form_list > li .input_file_box {justify-content: space-between;} - .add_form_list > li .input_file_box .file_add_wrap {position: relative; width: calc(50% - 5px); height: 0; padding-top: calc(50% - 5px);} - .add_form_list > li .input_file_box label {position: absolute; top: 0; left: 0; width: 100%; height: 100%;} + .add_form_list > li .input_file_box { + justify-content: space-between; + } + .add_form_list > li .input_file_box .file_add_wrap { + position: relative; + width: calc(50% - 5px); + height: 0; + padding-top: calc(50% - 5px); + } + .add_form_list > li .input_file_box label { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + } - .add_form_list > li .input_file_box:has( .limit_text.active) .file_add_wrap {padding-top: calc(50% + 15px);} - .add_form_list > li .input_file_box:has( .limit_text.active) label {height: calc(100% - 20px);} + .add_form_list > li .input_file_box:has(.limit_text.active) .file_add_wrap { + padding-top: calc(50% + 15px); + } + .add_form_list > li .input_file_box:has(.limit_text.active) label { + height: calc(100% - 20px); + } - .add_form_list > li .input_file_box .file_img_list {position: relative; width: calc(50% - 5px); height: 0; padding-top: calc(50% - 5px);} - .add_form_list > li .input_file_box .file_img_list > li {position: absolute; top: 0; left: 0; width: 100%; height: 100%; margin-left: 0;} + .add_form_list > li .input_file_box .file_img_list { + position: relative; + width: calc(50% - 5px); + height: 0; + padding-top: calc(50% - 5px); + } + .add_form_list > li .input_file_box .file_img_list > li { + position: absolute; + top: 0; + left: 0; + width: 100%; + height: 100%; + margin-left: 0; + } - .limit_text {margin-top: -50px;} - .limit_text.active {margin-top: -13px;} + .limit_text { + margin-top: -50px; + } + .limit_text.active { + margin-top: -13px; + } } diff --git a/src/components/FileInput.jsx b/src/components/FileInput.tsx similarity index 64% rename from src/components/FileInput.jsx rename to src/components/FileInput.tsx index b874bd157..f8344f8a4 100644 --- a/src/components/FileInput.jsx +++ b/src/components/FileInput.tsx @@ -2,16 +2,25 @@ import addImg from "./../assets/icon_add.svg"; import removeIcon from "./../assets/icon_remove.svg"; import { useEffect, useState, useRef } from "react"; import "./FileInput.css"; +import { ItemInputQuery } from "../types/Query"; -function FileInput({ name, value, onChange }) { - const handleFileChange = (e) => { - onChange(name, e.target.files[0]); +interface Props { + name: ItemInputQuery; + value: File; + onChange: (name: ItemInputQuery, value: File | null) => void; +} + +function FileInput({ name, value, onChange }: Props) { + const handleFileChange = (e: React.ChangeEvent) => { + if (e.target.files) { + onChange(name, e.target.files[0]); + } }; const [fileImg, setFileImg] = useState(""); const [limit, setLimit] = useState(false); - const fileInputRef = useRef(null); + const fileInputRef = useRef(null); useEffect(() => { if (value) { @@ -22,22 +31,22 @@ function FileInput({ name, value, onChange }) { } }, [value]); - const handlePreviewRemove = (e) => { + const handlePreviewRemove = (e: React.MouseEvent) => { setFileImg(""); onChange(name, null); if (fileInputRef.current) { - fileInputRef.current.value = null; + fileInputRef.current.value = ""; } }; - const handleAddLimit = () => { + const handleAddLimit = (e: React.MouseEvent) => { setLimit(true); }; return ( <>
-