diff --git a/.eslintrc.cjs b/.eslintrc.cjs index 3e212e1..f72df80 100644 --- a/.eslintrc.cjs +++ b/.eslintrc.cjs @@ -6,16 +6,41 @@ module.exports = { 'plugin:react/recommended', 'plugin:react/jsx-runtime', 'plugin:react-hooks/recommended', + 'plugin: prettier/recommended', + 'react-app', ], ignorePatterns: ['dist', '.eslintrc.cjs'], parserOptions: { ecmaVersion: 'latest', sourceType: 'module' }, settings: { react: { version: '18.2' } }, plugins: ['react-refresh'], rules: { + 'no-var': 'warn', // var 금지 + 'no-multiple-empty-lines': 'warn', // 여러 줄 공백 금지 + 'no-console': ['warn', { allow: ['warn', 'error'] }], // console.log() 금지 + eqeqeq: 'warn', // 일치 연산자 사용 필수 + 'dot-notation': 'warn', // 가능하다면 dot notation 사용 + 'no-unused-vars': 'warn', // 사용하지 않는 변수 금지 + 'react/destructuring-assignment': 'warn', // state, prop 등에 구조분해 할당 적용 + 'react/jsx-pascal-case': 'warn', // 컴포넌트 이름은 PascalCase로 + 'react/no-direct-mutation-state': 'warn', // state 직접 수정 금지 + 'react/jsx-no-useless-fragment': 'warn', // 불필요한 fragment 금지 + 'react/no-unused-state': 'warn', // 사용되지 않는 state + 'react/jsx-key': 'warn', // 반복문으로 생성하는 요소에 key 강제 + 'react/self-closing-comp': 'warn', // 셀프 클로징 태그 가능하면 적용 + 'react/jsx-curly-brace-presence': 'warn', // jsx 내 불필요한 중괄호 금지 + 'prettier/prettier': [ + 'error', + { + endOfLine: 'auto', + }, + ], + env: { + browser: true, // document, window 등의 브라우저 내장 객체들 조회시 ESLint 오류 없이 작업 + }, 'react/jsx-no-target-blank': 'off', 'react-refresh/only-export-components': [ 'warn', { allowConstantExport: true }, ], }, -} +}; diff --git a/.prettierrc b/.prettierrc new file mode 100644 index 0000000..5a01fba --- /dev/null +++ b/.prettierrc @@ -0,0 +1,6 @@ +{ + "tabWidth": 2, + "endOfLine": "lf", + "arrowParens": "avoid", + "singleQuote": true +} diff --git a/.vscode/extensions.json b/.vscode/extensions.json new file mode 100644 index 0000000..ff1b97a --- /dev/null +++ b/.vscode/extensions.json @@ -0,0 +1,3 @@ +{ + "recommendations": ["streetsidesoftware.code-spell-checker"] +} diff --git a/package-lock.json b/package-lock.json index 65af28b..bda5dc9 100644 --- a/package-lock.json +++ b/package-lock.json @@ -25,10 +25,13 @@ "@types/react-dom": "^18.2.22", "@vitejs/plugin-react": "^4.2.1", "eslint": "^8.57.0", + "eslint-config-prettier": "^9.1.0", + "eslint-plugin-prettier": "^5.1.3", "eslint-plugin-react": "^7.34.1", "eslint-plugin-react-hooks": "^4.6.0", "eslint-plugin-react-refresh": "^0.4.6", "json-server": "^0.17.4", + "prettier": "^3.2.5", "vite": "^5.2.0" } }, @@ -955,6 +958,18 @@ "node": ">= 8" } }, + "node_modules/@pkgr/core": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/@pkgr/core/-/core-0.1.1.tgz", + "integrity": "sha512-cq8o4cWH0ibXh9VGi5P20Tu9XF/0fFXl9EUinr9QfTM7a7p0oTA4iJRCQWppXR1Pg8dSM0UCItCkPwsk9qWWYA==", + "dev": true, + "engines": { + "node": "^12.20.0 || ^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/unts" + } + }, "node_modules/@remix-run/router": { "version": "1.15.3", "resolved": "https://registry.npmjs.org/@remix-run/router/-/router-1.15.3.tgz", @@ -2414,6 +2429,48 @@ "url": "https://opencollective.com/eslint" } }, + "node_modules/eslint-config-prettier": { + "version": "9.1.0", + "resolved": "https://registry.npmjs.org/eslint-config-prettier/-/eslint-config-prettier-9.1.0.tgz", + "integrity": "sha512-NSWl5BFQWEPi1j4TjVNItzYV7dZXZ+wP6I6ZhrBGpChQhZRUaElihE9uRRkcbRnNb76UMKDF3r+WTmNcGPKsqw==", + "dev": true, + "bin": { + "eslint-config-prettier": "bin/cli.js" + }, + "peerDependencies": { + "eslint": ">=7.0.0" + } + }, + "node_modules/eslint-plugin-prettier": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/eslint-plugin-prettier/-/eslint-plugin-prettier-5.1.3.tgz", + "integrity": "sha512-C9GCVAs4Eq7ZC/XFQHITLiHJxQngdtraXaM+LoUFoFp/lHNl2Zn8f3WQbe9HvTBBQ9YnKFB0/2Ajdqwo5D1EAw==", + "dev": true, + "dependencies": { + "prettier-linter-helpers": "^1.0.0", + "synckit": "^0.8.6" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/eslint-plugin-prettier" + }, + "peerDependencies": { + "@types/eslint": ">=8.0.0", + "eslint": ">=8.0.0", + "eslint-config-prettier": "*", + "prettier": ">=3.0.0" + }, + "peerDependenciesMeta": { + "@types/eslint": { + "optional": true + }, + "eslint-config-prettier": { + "optional": true + } + } + }, "node_modules/eslint-plugin-react": { "version": "7.34.1", "resolved": "https://registry.npmjs.org/eslint-plugin-react/-/eslint-plugin-react-7.34.1.tgz", @@ -2780,6 +2837,12 @@ "integrity": "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q==", "dev": true }, + "node_modules/fast-diff": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/fast-diff/-/fast-diff-1.3.0.tgz", + "integrity": "sha512-VxPP4NqbUjj6MaAOafWeUn2cXWLcCtljklUtZf0Ind4XQ+QPtmA0b18zZy0jIQx+ExRVCR/ZQpBmik5lXshNsw==", + "dev": true + }, "node_modules/fast-json-stable-stringify": { "version": "2.1.0", "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.1.0.tgz", @@ -4529,6 +4592,33 @@ "node": ">= 0.8.0" } }, + "node_modules/prettier": { + "version": "3.2.5", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.2.5.tgz", + "integrity": "sha512-3/GWa9aOC0YeD7LUfvOG2NiDyhOWRvt1k+rcKhOuYnMY24iiCphgneUfJDyFXd6rZCAnuLBv6UeAULtrhT/F4A==", + "dev": true, + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + }, + "node_modules/prettier-linter-helpers": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/prettier-linter-helpers/-/prettier-linter-helpers-1.0.0.tgz", + "integrity": "sha512-GbK2cP9nraSSUF9N2XwUwqfzlAFlMNYYl+ShE/V+H8a9uNl/oUqB1w2EL54Jh0OlyRSd8RfWYJ3coVS4TROP2w==", + "dev": true, + "dependencies": { + "fast-diff": "^1.1.2" + }, + "engines": { + "node": ">=6.0.0" + } + }, "node_modules/process-nextick-args": { "version": "2.0.1", "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz", @@ -5385,6 +5475,28 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/synckit": { + "version": "0.8.8", + "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.8.8.tgz", + "integrity": "sha512-HwOKAP7Wc5aRGYdKH+dw0PRRpbO841v2DENBtjnR5HFWoiNByAl7vrx3p0G/rCyYXQsrxqtX48TImFtPcIHSpQ==", + "dev": true, + "dependencies": { + "@pkgr/core": "^0.1.0", + "tslib": "^2.6.2" + }, + "engines": { + "node": "^14.18.0 || >=16.0.0" + }, + "funding": { + "url": "https://opencollective.com/unts" + } + }, + "node_modules/synckit/node_modules/tslib": { + "version": "2.6.2", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz", + "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q==", + "dev": true + }, "node_modules/text-table": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/text-table/-/text-table-0.2.0.tgz", diff --git a/package.json b/package.json index 0c19490..2e20cf1 100644 --- a/package.json +++ b/package.json @@ -28,10 +28,13 @@ "@types/react-dom": "^18.2.22", "@vitejs/plugin-react": "^4.2.1", "eslint": "^8.57.0", + "eslint-config-prettier": "^9.1.0", + "eslint-plugin-prettier": "^5.1.3", "eslint-plugin-react": "^7.34.1", "eslint-plugin-react-hooks": "^4.6.0", "eslint-plugin-react-refresh": "^0.4.6", "json-server": "^0.17.4", + "prettier": "^3.2.5", "vite": "^5.2.0" } } diff --git a/src/api/WastesApi.jsx b/src/api/WastesApi.jsx index 176029d..707ebe1 100644 --- a/src/api/WastesApi.jsx +++ b/src/api/WastesApi.jsx @@ -28,3 +28,8 @@ export const deletePost = async (wasteId) => { throw error; // 오류를 다시 throw하여 컴포넌트에서 처리할 수 있도록 함 } }; + +export const updatePost = async (wasteId, updatedPost) => { + const response = await axios.put(`${API_URL}/wastes/${wasteId}`, updatedPost); + return response.data; +}; diff --git a/src/components/ProductCard.jsx b/src/components/ProductCard.jsx new file mode 100644 index 0000000..c9bc366 --- /dev/null +++ b/src/components/ProductCard.jsx @@ -0,0 +1,71 @@ +import React, { useState } from 'react'; +import * as S from '../styles/ProductCardStyle'; +import { GoHeart } from 'react-icons/go'; +import { GoHeartFill } from 'react-icons/go'; +import { useRecoilState } from 'recoil'; +import { postsState } from '../recoil/RecoilWastes'; +import { useEffect } from 'react'; +import { fetchPosts } from '../api/WastesApi'; +import { updatePost } from '../api/WastesApi'; +const ProductCard = ({ post, onDelete }) => { + const handleDeleteClick = () => { + onDelete(post.id); + }; + + const [posts, setPosts] = useRecoilState(postsState); + + const handleLikeToggle = async () => { + const updatedPost = { ...post }; + if (updatedPost.hearted) { + updatedPost.likeCount -= 1; // 채워진 하트에서 빈 하트로 변경되면 likeCount 감소 + } else { + updatedPost.likeCount += 1; // 빈 하트에서 채워진 하트로 변경되면 likeCount 증가 + } + updatedPost.hearted = !updatedPost.hearted; // 하트 상태 업데이트 + await updatePost(post.id, updatedPost); // 서버에 업데이트 요청 + const updatedPosts = posts.map(p => (p.id === post.id ? updatedPost : p)); + setPosts(updatedPosts); // Recoil 상태 업데이트 + }; + return ( +
+ +
+
+ 임시이미지 +
+
{post.title}
+
+
+
{post.address.state}
+
{post.address.city}
+
+
+ {/* */} + {/*
{wastes.created_at}
*/} +
+
+
{post.wastePrice}원
+
+
+
+

{post.sellStatus}

+
+ +
{post.likeCount}
+
+
+ {/* */} + {/* */} +
+
+
+ ); +}; + +export default ProductCard; diff --git a/src/fakeServer/db.json b/src/fakeServer/db.json index cc07d9f..7f3adf4 100644 --- a/src/fakeServer/db.json +++ b/src/fakeServer/db.json @@ -2,24 +2,304 @@ "wastes": [ { "fileName": {}, - "title": "예시", + "title": "옷팝니다.", "wasteCategory": "의류", + "wasteStatus": "중", + "sellStatus": "거래중", + "wastePrice": "2,000", + "content": "ㅇㅇㅇㅇㅇㅇㅇㅇㅇ", + "address": { + "address": "경기 안성시 고삼면 안성대로 1980", + "zipcode": "17505", + "state": "경기", + "city": "안성시", + "district": "가유리", + "detail": "" + }, + "likeCount": 50, + "viewCount": 55, + "created_at": "2024. 4. 11.", + "id": 1 + }, + { + "fileName": {}, + "title": "화장품 팝니다.", + "wasteCategory": "뷰티", + "wasteStatus": "하", + "sellStatus": "거래중", + "wastePrice": "2,500", + "content": "팔아요", + "address": { + "address": "인천 강화군 강화읍 갑룡길 35", + "zipcode": "23024", + "state": "인천", + "city": "강화군", + "district": "갑곳리", + "detail": "그랑드빌 아파트" + }, + "likeCount": 40, + "viewCount": 45, + "created_at": "2024. 4. 11.", + "id": 2 + }, + { + "fileName": {}, + "title": "핸드폰 팔아요", + "wasteCategory": "전자기기", + "wasteStatus": "최상", + "sellStatus": "거래중", + "wastePrice": "10,000", + "content": "팝니다.", + "address": { + "address": "서울 성동구 서울숲길 17", + "zipcode": "04766", + "state": "서울", + "city": "성동구", + "district": "성수동1가", + "detail": "성수파크빌" + }, + "likeCount": 60, + "viewCount": 72, + "created_at": "2024. 4. 11.", + "id": 3 + }, + { + "fileName": {}, + "title": "안녕하세요", + "wasteCategory": "뷰티", + "wasteStatus": "최하", + "sellStatus": "거래중", + "wastePrice": "0", + "content": "나눔합니다.", + "address": { + "address": "서울 종로구 북촌로 31-4", + "zipcode": "03055", + "state": "서울", + "city": "종로구", + "district": "가회동", + "detail": "오픈아이즈센터" + }, + "likeCount": 60, + "viewCount": 72, + "created_at": "2024. 4. 11.", + "id": 4, + "hearted": false + }, + { + "fileName": {}, + "title": "가구나눔", + "wasteCategory": "가구/인텔어", + "wasteStatus": "최상", + "sellStatus": "거래중", + "wastePrice": "0", + "content": "ddfweg", + "address": { + "address": "인천 부평구 갈산로 2", + "zipcode": "21316", + "state": "인천", + "city": "부평구", + "district": "갈산동", + "detail": "" + }, + "likeCount": 88, + "viewCount": 100, + "created_at": "2024. 4. 11.", + "id": 6, + "hearted": false + }, + { + "fileName": {}, + "title": "씨앗 팔아요", + "wasteCategory": "식물", + "wasteStatus": "최상", + "sellStatus": "거래중", + "wastePrice": "500", + "content": "ㅇㅇㅇㄴㄹㄷ", + "address": { + "address": "서울 강남구 가로수길 5", + "zipcode": "06035", + "state": "서울", + "city": "강남구", + "district": "신사동", + "detail": "" + }, + "likeCount": 100, + "viewCount": 25, + "created_at": "2024. 4. 11.", + "id": 7, + "hearted": false + }, + { + "fileName": {}, + "title": "건강식품", + "wasteCategory": "건강", + "wasteStatus": "중", + "sellStatus": "거래중", + "wastePrice": "4,000", + "content": "건강식품", + "address": { + "address": "서울 용산구 두텁바위로 5", + "zipcode": "04335", + "state": "서울", + "city": "용산구", + "district": "갈월동", + "detail": "" + }, + "likeCount": 70, + "viewCount": 55, + "created_at": "2024. 4. 12.", + "id": 8 + }, + { + "fileName": {}, + "title": "ㄹㄹㄹㄹㄹㄹㄹ", + "wasteCategory": "뷰티", + "wasteStatus": "최하", + "sellStatus": "거래중", + "wastePrice": "5,000", + "content": "뷰티", + "address": { + "address": "인천 미추홀구 남주길 5", + "zipcode": "22156", + "state": "인천", + "city": "미추홀구", + "district": "주안동", + "detail": "" + }, + "likeCount": 70, + "viewCount": 55, + "created_at": "2024. 4. 12.", + "id": 9 + }, + { + "fileName": {}, + "title": "ㅇㅇㅇㅇㅇㅇ", + "wasteCategory": "뷰티", + "wasteStatus": "하", + "sellStatus": "거래중", + "wastePrice": "0", + "content": "dddddddd", + "address": { + "address": "서울 송파구 성남대로 1541-40", + "zipcode": "05843", + "state": "서울", + "city": "송파구", + "district": "장지동", + "detail": "" + }, + "likeCount": 70, + "viewCount": 55, + "created_at": "2024. 4. 12.", + "id": 10 + }, + { + "fileName": {}, + "title": "뷰티", + "wasteCategory": "뷰티", + "wasteStatus": "최하", + "sellStatus": "거래중", + "wastePrice": "500", + "content": "뷰티템", + "address": { + "address": "서울 은평구 갈현로 181-2", + "zipcode": "03325", + "state": "서울", + "city": "은평구", + "district": "갈현동", + "detail": "" + }, + "likeCount": 70, + "viewCount": 55, + "created_at": "2024. 4. 12.", + "id": 11, + "hearted": false + }, + { + "fileName": {}, + "title": "뷰티템5개", + "wasteCategory": "뷰티", "wasteStatus": "상", "sellStatus": "거래중", + "wastePrice": "8,000", + "content": "5개팔아요", + "address": { + "address": "인천 남동구 간석로 1", + "zipcode": "21510", + "state": "인천", + "city": "남동구", + "district": "간석동", + "detail": "" + }, + "likeCount": 70, + "viewCount": 55, + "created_at": "2024. 4. 12.", + "id": 12, + "hearted": false + }, + { + "fileName": {}, + "title": "xx립스틱", + "wasteCategory": "뷰티", + "wasteStatus": "중", + "sellStatus": "거래중", + "wastePrice": "50,000", + "content": "새거 팝니다.", + "address": { + "address": "서울 용산구 남산공원길 101", + "zipcode": "04340", + "state": "서울", + "city": "용산구", + "district": "후암동", + "detail": "" + }, + "likeCount": 70, + "viewCount": 55, + "created_at": "2024. 4. 12.", + "id": 13, + "hearted": false + }, + { + "fileName": {}, + "title": "사세요~", + "wasteCategory": "뷰티", + "wasteStatus": "최상", + "sellStatus": "거래중", + "wastePrice": "50,000", + "content": "가져가세요~", + "address": { + "address": "경기 부천시 소사구 부천로 1", + "zipcode": "14637", + "state": "경기", + "city": "부천시 소사구", + "district": "심곡본동", + "detail": "부천역사 쇼핑몰" + }, + "likeCount": 70, + "viewCount": 55, + "created_at": "2024. 4. 12.", + "id": 14, + "hearted": false + }, + { + "fileName": {}, + "title": "ddfdd", + "wasteCategory": "의류", + "wasteStatus": "중", + "sellStatus": "", "wastePrice": "3,000", - "content": "예시입니다.", + "content": "ddddd", "address": { - "address": "서울 서초구 안골길 4", - "zipcode": "06794", + "address": "서울 마포구 굴레방로 1", + "zipcode": "04117", "state": "서울", - "city": "서초구", - "district": "내곡동", + "city": "마포구", + "district": "아현동", "detail": "" }, - "likeCount": "", - "viewCount": "", - "created_at": "2024. 4. 11.", - "id": 1 + "likeCount": 70, + "viewCount": 55, + "created_at": "2024. 4. 13.", + "id": 15 } ] } \ No newline at end of file diff --git a/src/index.css b/src/index.css index cd7c391..5410a08 100644 --- a/src/index.css +++ b/src/index.css @@ -32,6 +32,7 @@ --grey-dgrey: #34495e; --grey-dark: #353e4a; --grey-box: #d9d9d9; + --grey-light: #f0f0f0; --white-ivory: #fbf8ef; } @@ -123,3 +124,6 @@ video { font: inherit; vertical-align: baseline; } +ul { + list-style: none; +} diff --git a/src/pages/ProductAdd.jsx b/src/pages/ProductAdd.jsx index 2ad9eda..c40ab4c 100644 --- a/src/pages/ProductAdd.jsx +++ b/src/pages/ProductAdd.jsx @@ -1,37 +1,37 @@ -import React, { useState } from "react"; -import { useRecoilState } from "recoil"; -import Nav from "../components/Nav"; -import { FaWonSign } from "react-icons/fa6"; -import { IoIosArrowForward } from "react-icons/io"; -import * as S from "../styles/ProductAddStyle"; -import { Link, Navigate, useNavigate } from "react-router-dom"; -import { postsState } from "../recoil/RecoilWastes"; -import { createPost } from "../api/WastesApi"; -import { IoIosCamera } from "react-icons/io"; -import axios from "axios"; +import React, { useState } from 'react'; +import { useRecoilState } from 'recoil'; +import Nav from '../components/Nav'; +import { FaWonSign } from 'react-icons/fa6'; +import { IoIosArrowForward } from 'react-icons/io'; +import * as S from '../styles/ProductAddStyle'; +import { Link, Navigate, useNavigate } from 'react-router-dom'; +import { postsState } from '../recoil/RecoilWastes'; +import { createPost } from '../api/WastesApi'; +import { IoIosCamera } from 'react-icons/io'; +import axios from 'axios'; const ProductAdd = () => { const [posts, setPosts] = useRecoilState(postsState); - const [wasteCategory, setWasteCategory] = useState(""); - const [title, setTitle] = useState(""); - const [wasteStatus, setWasteStatus] = useState(""); - const [content, setContent] = useState(""); - const [sellStatus, setSellStatus] = useState(""); - const [wastePrice, setWastePrice] = useState(""); + const [wasteCategory, setWasteCategory] = useState(''); + const [title, setTitle] = useState(''); + const [wasteStatus, setWasteStatus] = useState(''); + const [content, setContent] = useState(''); + const [sellStatus, setSellStatus] = useState(''); + const [wastePrice, setWastePrice] = useState(''); const [address, setAddress] = useState({ - zipcode: "", - state: "", - city: "", - district: "", - detail: "", + zipcode: '', + state: '', + city: '', + district: '', + detail: '', }); const [fileName, setFileName] = useState(null); - const [likeCount, setLikeCount] = useState(""); - const [viewCount, setViewCount] = useState(""); + const [likeCount, setLikeCount] = useState(70); + const [viewCount, setViewCount] = useState(55); const navigate = useNavigate(); //찾은 주소 inptu 반영 - const handleComplete = (data) => { + const handleComplete = data => { setAddress({ address: data.address, zipcode: data.zonecode, @@ -48,14 +48,14 @@ const ProductAdd = () => { }).open(); }; //이미지 형식 제한 - const validImageTypes = ["image/jpeg", "image/jpg", "image/png"]; - const handleImageChange = (e) => { + const validImageTypes = ['image/jpeg', 'image/jpg', 'image/png']; + const handleImageChange = e => { const file = e.target.files[0]; if (file) { if (validImageTypes.includes(file.type)) { setFileName(file); } else { - alert("올바른 이미지 형식을 선택하세요. (JPEG, JPG, PNG)"); + alert('올바른 이미지 형식을 선택하세요. (JPEG, JPG, PNG)'); // 선택한 파일 초기화 e.target.value = null; } @@ -63,47 +63,47 @@ const ProductAdd = () => { }; //데이터 제출 - const handlePriceChange = (str) => { - const comma = (str) => { + const handlePriceChange = str => { + const comma = str => { str = String(str); - return str.replace(/(\d)(?=(?:\d{3})+(?!\d))/g, "$1,"); + return str.replace(/(\d)(?=(?:\d{3})+(?!\d))/g, '$1,'); }; - const uncomma = (str) => { + const uncomma = str => { str = String(str); - return str.replace(/[^\d]+/g, ""); + return str.replace(/[^\d]+/g, ''); }; return comma(uncomma(str)); }; //제목 글자수 제한 - const handleTitleChange = (e) => { + const handleTitleChange = e => { const inputValue = e.target.value; if (inputValue.length <= 255) { setTitle(inputValue); } }; //내용 글자수 제한 - const handleContentChange = (e) => { + const handleContentChange = e => { const inputValue = e.target.value; if (inputValue.length <= 65535) { setContent(inputValue); } }; - const handleSubmit = async (e) => { + const handleSubmit = async e => { e.preventDefault(); const formData = new FormData(); - formData.append("fileName", fileName); - formData.append("category", wasteCategory); - formData.append("title", title); - formData.append("waste_status", wasteStatus); - formData.append("sell_status", sellStatus); - formData.append("waste_price", wastePrice); - formData.append("content", content); - formData.append("address", address); - formData.append("likeCount", likeCount); - formData.append("viewCount", viewCount); + formData.append('fileName', fileName); + formData.append('category', wasteCategory); + formData.append('title', title); + formData.append('waste_status', wasteStatus); + formData.append('sell_status', sellStatus); + formData.append('waste_price', wastePrice); + formData.append('content', content); + formData.append('address', address); + formData.append('likeCount', likeCount); + formData.append('viewCount', viewCount); try { const newPost = { @@ -122,18 +122,18 @@ const ProductAdd = () => { const createdPost = await createPost(newPost); setPosts([...posts, createdPost]); - setWasteCategory(""); - setTitle(""); - setWasteStatus(""); - setContent(""); - setSellStatus(""); - setWastePrice(""); - setAddress(""); + setWasteCategory(''); + setTitle(''); + setWasteStatus(''); + setContent(''); + setSellStatus(''); + setWastePrice(''); + setAddress(''); setFileName(null); - navigate("/ProductsList"); + navigate('/ProductsList'); } catch (error) { - console.error("Error uploading image:", error); + console.error('Error uploading image:', error); } }; return ( @@ -173,7 +173,7 @@ const ProductAdd = () => { setWasteStatus(e.target.value)} + checked={wasteStatus === '중'} + onChange={e => setWasteStatus(e.target.value)} /> setWasteStatus(e.target.value)} + checked={wasteStatus === '하'} + onChange={e => setWasteStatus(e.target.value)} /> setWasteStatus(e.target.value)} + checked={wasteStatus === '최하'} + onChange={e => setWasteStatus(e.target.value)} /> -
+ {/*
@@ -261,8 +261,8 @@ const ProductAdd = () => { -
- {wastePrice.startsWith("0") ? ( +
*/} + {wastePrice.startsWith('0') ? (