diff --git a/package-lock.json b/package-lock.json index 6c48b1fa..6c4e8dba 100644 --- a/package-lock.json +++ b/package-lock.json @@ -11,6 +11,11 @@ "@testing-library/jest-dom": "^5.17.0", "@testing-library/react": "^13.4.0", "@testing-library/user-event": "^13.5.0", + "@types/jest": "^29.5.14", + "@types/node": "^22.13.5", + "@types/react": "^19.0.10", + "@types/react-dom": "^19.0.4", + "@types/styled-components": "^5.1.34", "axios": "^1.7.9", "lodash.debounce": "^4.0.8", "react": "^18.2.0", @@ -20,6 +25,11 @@ "react-scripts": "5.0.1", "styled-components": "^6.1.14", "web-vitals": "^2.1.4" + }, + "devDependencies": { + "@types/lodash.debounce": "^4.0.9", + "@types/react-js-pagination": "^3.0.7", + "typescript": "^4.9.5" } }, "node_modules/@aashutoshrathi/word-wrap": { @@ -3805,6 +3815,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/ansi-styles": { "version": "4.3.0", "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz", @@ -4037,6 +4065,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", @@ -4077,9 +4114,9 @@ } }, "node_modules/@types/jest": { - "version": "29.5.4", - "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.5.4.tgz", - "integrity": "sha512-PhglGmhWeD46FYOVLt3X7TiWjzwuVGW9wG/4qocPevXMjCmrIc5b6db9WjeGE4QYVpUAWMDv3v0IiBwObY289A==", + "version": "29.5.14", + "resolved": "https://registry.npmjs.org/@types/jest/-/jest-29.5.14.tgz", + "integrity": "sha512-ZN+4sdnLUbo8EVvVc2ao0GFW6oVrQRPn4K2lglySj7APvSrgzxHiNNK99us4WDMi57xxA2yggblIAMNhXOotLQ==", "dependencies": { "expect": "^29.0.0", "pretty-format": "^29.0.0" @@ -4322,15 +4359,33 @@ "resolved": "https://registry.npmjs.org/@types/json5/-/json5-0.0.29.tgz", "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==" }, + "node_modules/@types/lodash": { + "version": "4.17.15", + "resolved": "https://registry.npmjs.org/@types/lodash/-/lodash-4.17.15.tgz", + "integrity": "sha512-w/P33JFeySuhN6JLkysYUK2gEmy9kHHFN7E8ro0tkfmlDOgxBDzWEZ/J8cWA+fHqFevpswDTFZnDx+R9lbL6xw==", + "dev": true + }, + "node_modules/@types/lodash.debounce": { + "version": "4.0.9", + "resolved": "https://registry.npmjs.org/@types/lodash.debounce/-/lodash.debounce-4.0.9.tgz", + "integrity": "sha512-Ma5JcgTREwpLRwMM+XwBR7DaWe96nC38uCBDFKZWbNKD+osjVzdpnUSwBcqCptrp16sSOLBAUb50Car5I0TCsQ==", + "dev": true, + "dependencies": { + "@types/lodash": "*" + } + }, "node_modules/@types/mime": { "version": "1.3.2", "resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.2.tgz", "integrity": "sha512-YATxVxgRqNH6nHEIsvg6k2Boc1JHI9ZbH5iWFFv/MTkchz3b1ieGDa5T0a9RznNdI0KhVbdbWSN+KWWrQZRxTw==" }, "node_modules/@types/node": { - "version": "20.5.9", - "resolved": "https://registry.npmjs.org/@types/node/-/node-20.5.9.tgz", - "integrity": "sha512-PcGNd//40kHAS3sTlzKB9C9XL4K0sTup8nbG5lC14kzEteTNuAFh9u5nA0o5TWnSG2r/JNPRXFVcHJIIeRlmqQ==" + "version": "22.13.5", + "resolved": "https://registry.npmjs.org/@types/node/-/node-22.13.5.tgz", + "integrity": "sha512-+lTU0PxZXn0Dr1NBtC7Y8cR21AJr87dLLU953CWA6pMxxv/UDc7jYAY90upcrie1nRcD6XNG5HOYEDtgW5TxAg==", + "dependencies": { + "undici-types": "~6.20.0" + } }, "node_modules/@types/parse-json": { "version": "4.0.0", @@ -4343,9 +4398,10 @@ "integrity": "sha512-+68kP9yzs4LMp7VNh8gdzMSPZFL44MLGqiHWvttYJe+6qnuVr4Ek9wSBQoveqY/r+LwjCcU29kNVkidwim+kYA==" }, "node_modules/@types/prop-types": { - "version": "15.7.5", - "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.5.tgz", - "integrity": "sha512-JCB8C6SnDoQf0cNycqd/35A7MjcnK+ZTqE7judS6o7utxUCg6imJg3QK2qzHKszlTjcj2cn+NwMB2i96ubpj7w==" + "version": "15.7.14", + "resolved": "https://registry.npmjs.org/@types/prop-types/-/prop-types-15.7.14.tgz", + "integrity": "sha512-gNMvNH49DJ7OJYv+KAKn0Xp45p8PLl6zo2YnvDIbTd4J6MER2BmWN49TG7n9LvkyihINxeKW8+3bfS2yDC9dzQ==", + "peer": true }, "node_modules/@types/q": { "version": "1.5.6", @@ -4363,19 +4419,26 @@ "integrity": "sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==" }, "node_modules/@types/react": { - "version": "18.2.21", - "resolved": "https://registry.npmjs.org/@types/react/-/react-18.2.21.tgz", - "integrity": "sha512-neFKG/sBAwGxHgXiIxnbm3/AAVQ/cMRS93hvBpg8xYRbeQSPVABp9U2bRnPf0iI4+Ucdv3plSxKK+3CW2ENJxA==", + "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": "*", - "@types/scheduler": "*", "csstype": "^3.0.2" } }, "node_modules/@types/react-dom": { - "version": "18.2.7", - "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-18.2.7.tgz", - "integrity": "sha512-GRaAEriuT4zp9N4p1i8BDBYmEyfo+xQ3yHjJU4eiK5NDa1RmUZG+unZABUTK4/Ox/M+GaHwb6Ow8rUITrtjszA==", + "version": "19.0.4", + "resolved": "https://registry.npmjs.org/@types/react-dom/-/react-dom-19.0.4.tgz", + "integrity": "sha512-4fSQ8vWFkg+TGhePfUzVmat3eC14TXYSsiiDSLI0dVLsrm9gZFABjPy/Qu6TKgl1tq1Bu1yDsuQgY3A3DOjCcg==", + "peerDependencies": { + "@types/react": "^19.0.0" + } + }, + "node_modules/@types/react-js-pagination": { + "version": "3.0.7", + "resolved": "https://registry.npmjs.org/@types/react-js-pagination/-/react-js-pagination-3.0.7.tgz", + "integrity": "sha512-h16F5eFcVaTO5LTT5jJrvK8SxTlxkuv03ZKt/e6L3GPng/0TZTqhEKEyD8F5XksLeKBalsS1tTN2foJLWv/6mA==", + "dev": true, "dependencies": { "@types/react": "*" } @@ -4393,11 +4456,6 @@ "resolved": "https://registry.npmjs.org/@types/retry/-/retry-0.12.0.tgz", "integrity": "sha512-wWKOClTTiizcZhXnPY4wikVAwmdYHp8q6DmC+EJUzAMsycb7HB32Kh9RN4+0gExjmPmZSAQjgURXIGATPegAvA==" }, - "node_modules/@types/scheduler": { - "version": "0.16.3", - "resolved": "https://registry.npmjs.org/@types/scheduler/-/scheduler-0.16.3.tgz", - "integrity": "sha512-5cJ8CB4yAx7BH1oMvdU0Jh9lrEXyPkar6F9G/ERswkCuvP4KQZfZkSjcMbAICCpQTN4OuZn8tz0HiKv9TGZgrQ==" - }, "node_modules/@types/semver": { "version": "7.5.1", "resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.1.tgz", @@ -4443,6 +4501,16 @@ "resolved": "https://registry.npmjs.org/@types/stack-utils/-/stack-utils-2.0.1.tgz", "integrity": "sha512-Hl219/BT5fLAaz6NDkSuhzasy49dwQS/DSdu4MdggFB8zcXv7vflBI3xp7FEmkmdDkBUI2bPUNeMttp2knYdxw==" }, + "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", @@ -9018,6 +9086,19 @@ "he": "bin/he" } }, + "node_modules/hoist-non-react-statics": { + "version": "3.3.2", + "resolved": "https://registry.npmjs.org/hoist-non-react-statics/-/hoist-non-react-statics-3.3.2.tgz", + "integrity": "sha512-/gGivxi8JPKWNm/W0jSmzcMPpfpPLc3dY/6GxhX2hQ9iGj3aDfklV4ET7NjKpSinLpJ5vafa9iiGIEZg10SfBw==", + "dependencies": { + "react-is": "^16.7.0" + } + }, + "node_modules/hoist-non-react-statics/node_modules/react-is": { + "version": "16.13.1", + "resolved": "https://registry.npmjs.org/react-is/-/react-is-16.13.1.tgz", + "integrity": "sha512-24e6ynE2H+OKt4kqsOvNd8kBpV65zoxbA4BVsEOB3ARVWQki/DHzaUoC5KuON/BiccDaCCTZBuOcfZs70kR8bQ==" + }, "node_modules/hoopy": { "version": "0.1.4", "resolved": "https://registry.npmjs.org/hoopy/-/hoopy-0.1.4.tgz", @@ -16869,7 +16950,6 @@ "version": "4.9.5", "resolved": "https://registry.npmjs.org/typescript/-/typescript-4.9.5.tgz", "integrity": "sha512-1FXk9E2Hm+QzZQ7z+McJiHL4NW1F2EzMu9Nq9i3zAaGqibafqYwCVU6WyWAuyQRRzOlxou8xZSyXLEN8oKj24g==", - "peer": true, "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" @@ -16897,6 +16977,11 @@ "resolved": "https://registry.npmjs.org/underscore/-/underscore-1.12.1.tgz", "integrity": "sha512-hEQt0+ZLDVUMhebKxL4x1BTtDY7bavVofhZ9KZ4aI26X9SRaE+Y3m83XUL1UP2jn8ynjndwCCpEHdUG+9pP1Tw==" }, + "node_modules/undici-types": { + "version": "6.20.0", + "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-6.20.0.tgz", + "integrity": "sha512-Ny6QZ2Nju20vw1SRHe3d9jVu6gJ+4e3+MMpqu7pqE5HT6WsTSlce++GQmK5UXS8mzV8DSYHrQH+Xrf2jVcuKNg==" + }, "node_modules/unicode-canonical-property-names-ecmascript": { "version": "2.0.0", "resolved": "https://registry.npmjs.org/unicode-canonical-property-names-ecmascript/-/unicode-canonical-property-names-ecmascript-2.0.0.tgz", diff --git a/package.json b/package.json index 7c5a459a..691455b6 100644 --- a/package.json +++ b/package.json @@ -6,6 +6,11 @@ "@testing-library/jest-dom": "^5.17.0", "@testing-library/react": "^13.4.0", "@testing-library/user-event": "^13.5.0", + "@types/jest": "^29.5.14", + "@types/node": "^22.13.5", + "@types/react": "^19.0.10", + "@types/react-dom": "^19.0.4", + "@types/styled-components": "^5.1.34", "axios": "^1.7.9", "lodash.debounce": "^4.0.8", "react": "^18.2.0", @@ -39,5 +44,10 @@ "last 1 firefox version", "last 1 safari version" ] + }, + "devDependencies": { + "@types/lodash.debounce": "^4.0.9", + "@types/react-js-pagination": "^3.0.7", + "typescript": "^4.9.5" } } diff --git a/src/App.jsx b/src/App.tsx similarity index 100% rename from src/App.jsx rename to src/App.tsx diff --git a/src/api/comment.js b/src/api/comment.js deleted file mode 100644 index 609d6110..00000000 --- a/src/api/comment.js +++ /dev/null @@ -1,11 +0,0 @@ -import axios from "axios"; - -const BASE_URL = process.env.REACT_APP_BASE_URL; - -export async function getComments(productId) { - const response = await axios.get( - `${BASE_URL}/products/${productId}/comments?limit=3` - ); - - return response.data.list; -} diff --git a/src/api/comment.tsx b/src/api/comment.tsx new file mode 100644 index 00000000..b5311cba --- /dev/null +++ b/src/api/comment.tsx @@ -0,0 +1,24 @@ +import api from "./index"; + +export interface Comment { + id: number; + content: string; + createdAt: string; + updatedAt: string; + writer: { + id: number; + image: string | null; + nickname: string; + }; +} + +export async function getComments( + productId: string, + limit: number = 3 +): Promise { + const response = await api.get( + `/products/${productId}/comments?limit=${limit}` + ); + + return response.data.list; +} diff --git a/src/api/index.tsx b/src/api/index.tsx new file mode 100644 index 00000000..e9ddd6b1 --- /dev/null +++ b/src/api/index.tsx @@ -0,0 +1,12 @@ +import axios from "axios"; + +const BASE_URL = process.env.REACT_APP_BASE_URL; + +const api = axios.create({ + baseURL: BASE_URL, + headers: { + "Content-Type": "application/json", + }, +}); + +export default api; diff --git a/src/api/products.js b/src/api/products.js deleted file mode 100644 index 4f9bb5c2..00000000 --- a/src/api/products.js +++ /dev/null @@ -1,18 +0,0 @@ -import axios from "axios"; - -const BASE_URL = process.env.REACT_APP_BASE_URL; - -export async function getProducts(params) { - const { page, pageSize, orderBy, keyword } = params; - const response = await axios.get(`${BASE_URL}/products`, { - params: { page, pageSize, orderBy, keyword }, - }); - - return response.data; -} - -export async function getProductInfo(productId) { - const response = await axios.get(`${BASE_URL}/products/${productId}`); - - return response.data; -} diff --git a/src/api/products.tsx b/src/api/products.tsx new file mode 100644 index 00000000..42c1f452 --- /dev/null +++ b/src/api/products.tsx @@ -0,0 +1,40 @@ +import { AddItem } from "../components/pages/AddItemPage/AddItemPage"; +import api from "./index"; + +export interface Items { + id: string; + images: string; + name: string; + price: number; + favoriteCount: number; +} + +interface Params { + page: number; + pageSize: number; + orderBy: string; + keyword: string; +} + +export interface DetailItem extends Omit { + images: string | null; + favoriteCount: number; + createdAt: string; + updatedAt: string; + ownerNickname: string; +} + +export async function getProducts(params: Params) { + const { page, pageSize, orderBy, keyword } = params; + const response = await api.get(`/products`, { + params: { page, pageSize, orderBy, keyword }, + }); + + return response.data; +} + +export async function getProductInfo(productId: string): Promise { + const response = await api.get(`/products/${productId}`); + + return response.data; +} diff --git a/src/components/Comment/Comment.styles.jsx b/src/components/Comment/Comment.styles.tsx similarity index 100% rename from src/components/Comment/Comment.styles.jsx rename to src/components/Comment/Comment.styles.tsx diff --git a/src/components/Comment/Comment.jsx b/src/components/Comment/Comment.tsx similarity index 100% rename from src/components/Comment/Comment.jsx rename to src/components/Comment/Comment.tsx diff --git a/src/components/Comment/CommentInput.styles.jsx b/src/components/Comment/CommentInput.styles.tsx similarity index 100% rename from src/components/Comment/CommentInput.styles.jsx rename to src/components/Comment/CommentInput.styles.tsx diff --git a/src/components/Comment/CommentInput.jsx b/src/components/Comment/CommentInput.tsx similarity index 82% rename from src/components/Comment/CommentInput.jsx rename to src/components/Comment/CommentInput.tsx index 1b6129ee..e06f07b8 100644 --- a/src/components/Comment/CommentInput.jsx +++ b/src/components/Comment/CommentInput.tsx @@ -3,7 +3,7 @@ import * as S from "./CommentInput.styles"; import { useState } from "react"; export default function CommentInput() { - const [comment, setComment] = useState(""); + const [comment, setComment] = useState(""); return ( @@ -14,7 +14,9 @@ export default function CommentInput() { largeHeight="140px" isTextarea value={comment} - onChange={(e) => setComment(e.target.value)} + onChange={(e: React.ChangeEvent) => + setComment(e.target.value) + } />