diff --git a/weatherfit_refactoring/package-lock.json b/weatherfit_refactoring/package-lock.json index 35fd8b7..9a2c523 100644 --- a/weatherfit_refactoring/package-lock.json +++ b/weatherfit_refactoring/package-lock.json @@ -8,8 +8,11 @@ "name": "weatherfit_refectoring", "version": "0.1.0", "dependencies": { + "@types/jsonwebtoken": "^9.0.6", "axios": "^1.6.7", + "dompurify": "^3.0.11", "js-cookie": "^3.0.5", + "jsonwebtoken": "^9.0.2", "next": "14.0.4", "react": "^18", "react-dom": "^18", @@ -19,6 +22,7 @@ "zustand": "^4.4.7" }, "devDependencies": { + "@types/dompurify": "^3.0.5", "@types/js-cookie": "^3.0.6", "@types/node": "^20", "@types/react": "^18", @@ -455,6 +459,15 @@ "tslib": "^2.4.0" } }, + "node_modules/@types/dompurify": { + "version": "3.0.5", + "resolved": "https://registry.npmjs.org/@types/dompurify/-/dompurify-3.0.5.tgz", + "integrity": "sha512-1Wg0g3BtQF7sSb27fJQAKck1HECM6zV1EB66j8JH9i3LCjYabJa0FSdiSgsD5K/RbrsR0SiraKacLB+T8ZVYAg==", + "dev": true, + "dependencies": { + "@types/trusted-types": "*" + } + }, "node_modules/@types/js-cookie": { "version": "3.0.6", "resolved": "https://registry.npmjs.org/@types/js-cookie/-/js-cookie-3.0.6.tgz", @@ -467,11 +480,18 @@ "integrity": "sha512-dRLjCWHYg4oaA77cxO64oO+7JwCwnIzkZPdrrC71jQmQtlhM556pwKo5bUzqvZndkVbeFLIIi+9TC40JNF5hNQ==", "dev": true }, + "node_modules/@types/jsonwebtoken": { + "version": "9.0.6", + "resolved": "https://registry.npmjs.org/@types/jsonwebtoken/-/jsonwebtoken-9.0.6.tgz", + "integrity": "sha512-/5hndP5dCjloafCXns6SZyESp3Ldq7YjH3zwzwczYnjxIT0Fqzk5ROSYVGfFyczIue7IUEj8hkvLbPoLQ18vQw==", + "dependencies": { + "@types/node": "*" + } + }, "node_modules/@types/node": { "version": "20.10.6", "resolved": "https://registry.npmjs.org/@types/node/-/node-20.10.6.tgz", "integrity": "sha512-Vac8H+NlRNNlAmDfGUP7b5h/KA+AtWIzuXy0E6OyP8f1tCLYAtPvKRRDJjAPqhpCb0t6U2j7/xqAuLEebW2kiw==", - "dev": true, "dependencies": { "undici-types": "~5.26.4" } @@ -508,6 +528,12 @@ "integrity": "sha512-WZLiwShhwLRmeV6zH+GkbOFT6Z6VklCItrDioxUnv+u4Ll+8vKeFySoFyK/0ctcRpOmwAicELfmys1sDc/Rw+A==", "devOptional": true }, + "node_modules/@types/trusted-types": { + "version": "2.0.7", + "resolved": "https://registry.npmjs.org/@types/trusted-types/-/trusted-types-2.0.7.tgz", + "integrity": "sha512-ScaPdn1dQczgbl0QFTeTOmVHFULt394XJgOQNoyVhZ6r2vLnMLJfBPd53SB52T/3G36VI1/g2MZaX0cwDuXsfw==", + "dev": true + }, "node_modules/@typescript-eslint/parser": { "version": "6.17.0", "resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.17.0.tgz", @@ -1038,6 +1064,11 @@ "node": "^6 || ^7 || ^8 || ^9 || ^10 || ^11 || ^12 || >=13.7" } }, + "node_modules/buffer-equal-constant-time": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/buffer-equal-constant-time/-/buffer-equal-constant-time-1.0.1.tgz", + "integrity": "sha512-zRpUiDwd/xk6ADqPMATG8vc9VPrkck7T07OIx0gnjmJAnHnTVXNQG3vfvWNuiZIkwu9KrKdA1iJKfsfTVxE6NA==" + }, "node_modules/busboy": { "version": "1.6.0", "resolved": "https://registry.npmjs.org/busboy/-/busboy-1.6.0.tgz", @@ -1349,12 +1380,25 @@ "node": ">=6.0.0" } }, + "node_modules/dompurify": { + "version": "3.0.11", + "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-3.0.11.tgz", + "integrity": "sha512-Fan4uMuyB26gFV3ovPoEoQbxRRPfTu3CvImyZnhGq5fsIEO+gEFLp45ISFt+kQBWsK5ulDdT0oV28jS1UrwQLg==" + }, "node_modules/eastasianwidth": { "version": "0.2.0", "resolved": "https://registry.npmjs.org/eastasianwidth/-/eastasianwidth-0.2.0.tgz", "integrity": "sha512-I88TYZWc9XiYHRQ4/3c5rjjfgkjhLyW2luGIheGERbNQ6OY7yTybanSpDXZa8y7VUP9YmDcYa+eyq4ca7iLqWA==", "dev": true }, + "node_modules/ecdsa-sig-formatter": { + "version": "1.0.11", + "resolved": "https://registry.npmjs.org/ecdsa-sig-formatter/-/ecdsa-sig-formatter-1.0.11.tgz", + "integrity": "sha512-nagl3RYrbNv6kQkeJIpt6NJZy8twLB/2vtz6yN9Z4vRKHN4/QZJIEbqohALSgwKdnksuY3k5Addp5lg8sVoVcQ==", + "dependencies": { + "safe-buffer": "^5.0.1" + } + }, "node_modules/electron-to-chromium": { "version": "1.4.620", "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.4.620.tgz", @@ -2913,6 +2957,27 @@ "json5": "lib/cli.js" } }, + "node_modules/jsonwebtoken": { + "version": "9.0.2", + "resolved": "https://registry.npmjs.org/jsonwebtoken/-/jsonwebtoken-9.0.2.tgz", + "integrity": "sha512-PRp66vJ865SSqOlgqS8hujT5U4AOgMfhrwYIuIhfKaoSCZcirrmASQr8CX7cUg+RMih+hgznrjp99o+W4pJLHQ==", + "dependencies": { + "jws": "^3.2.2", + "lodash.includes": "^4.3.0", + "lodash.isboolean": "^3.0.3", + "lodash.isinteger": "^4.0.4", + "lodash.isnumber": "^3.0.3", + "lodash.isplainobject": "^4.0.6", + "lodash.isstring": "^4.0.1", + "lodash.once": "^4.0.0", + "ms": "^2.1.1", + "semver": "^7.5.4" + }, + "engines": { + "node": ">=12", + "npm": ">=6" + } + }, "node_modules/jsx-ast-utils": { "version": "3.3.5", "resolved": "https://registry.npmjs.org/jsx-ast-utils/-/jsx-ast-utils-3.3.5.tgz", @@ -2928,6 +2993,25 @@ "node": ">=4.0" } }, + "node_modules/jwa": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jwa/-/jwa-1.4.1.tgz", + "integrity": "sha512-qiLX/xhEEFKUAJ6FiBMbes3w9ATzyk5W7Hvzpa/SLYdxNtng+gcurvrI7TbACjIXlsJyr05/S1oUhZrc63evQA==", + "dependencies": { + "buffer-equal-constant-time": "1.0.1", + "ecdsa-sig-formatter": "1.0.11", + "safe-buffer": "^5.0.1" + } + }, + "node_modules/jws": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/jws/-/jws-3.2.2.tgz", + "integrity": "sha512-YHlZCB6lMTllWDtSPHz/ZXTsi8S00usEV6v1tjq8tOUZzw7DpSDWVXjXDre6ed1w/pd495ODpHZYSdkRTsa0HA==", + "dependencies": { + "jwa": "^1.4.1", + "safe-buffer": "^5.0.1" + } + }, "node_modules/keyv": { "version": "4.5.4", "resolved": "https://registry.npmjs.org/keyv/-/keyv-4.5.4.tgz", @@ -2998,12 +3082,47 @@ "url": "https://github.com/sponsors/sindresorhus" } }, + "node_modules/lodash.includes": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/lodash.includes/-/lodash.includes-4.3.0.tgz", + "integrity": "sha512-W3Bx6mdkRTGtlJISOvVD/lbqjTlPPUDTMnlXZFnVwi9NKJ6tiAk6LVdlhZMm17VZisqhKcgzpO5Wz91PCt5b0w==" + }, + "node_modules/lodash.isboolean": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isboolean/-/lodash.isboolean-3.0.3.tgz", + "integrity": "sha512-Bz5mupy2SVbPHURB98VAcw+aHh4vRV5IPNhILUCsOzRmsTmSQ17jIuqopAentWoehktxGd9e/hbIXq980/1QJg==" + }, + "node_modules/lodash.isinteger": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/lodash.isinteger/-/lodash.isinteger-4.0.4.tgz", + "integrity": "sha512-DBwtEWN2caHQ9/imiNeEA5ys1JoRtRfY3d7V9wkqtbycnAmTvRRmbHKDV4a0EYc678/dia0jrte4tjYwVBaZUA==" + }, + "node_modules/lodash.isnumber": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/lodash.isnumber/-/lodash.isnumber-3.0.3.tgz", + "integrity": "sha512-QYqzpfwO3/CWf3XP+Z+tkQsfaLL/EnUlXWVkIk5FUPc4sBdTehEqZONuyRt2P67PXAk+NXmTBcc97zw9t1FQrw==" + }, + "node_modules/lodash.isplainobject": { + "version": "4.0.6", + "resolved": "https://registry.npmjs.org/lodash.isplainobject/-/lodash.isplainobject-4.0.6.tgz", + "integrity": "sha512-oSXzaWypCMHkPC3NvBEaPHf0KsA5mvPrOPgQWDsbg8n7orZ290M0BmC/jgRZ4vcJ6DTAhjrsSYgdsW/F+MFOBA==" + }, + "node_modules/lodash.isstring": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/lodash.isstring/-/lodash.isstring-4.0.1.tgz", + "integrity": "sha512-0wJxfxH1wgO3GrbuP+dTTk7op+6L41QCXbGINEmD+ny/G/eCqGzxyCsh7159S+mgDDcoarnBw6PC1PS5+wUGgw==" + }, "node_modules/lodash.merge": { "version": "4.6.2", "resolved": "https://registry.npmjs.org/lodash.merge/-/lodash.merge-4.6.2.tgz", "integrity": "sha512-0KpjqXRVvrYyCsX1swR/XTK0va6VQkQM6MNo7PqW77ByjAhoARA8EfrP1N4+KlKj8YS0ZUCtRT/YUuhyYDujIQ==", "dev": true }, + "node_modules/lodash.once": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/lodash.once/-/lodash.once-4.1.1.tgz", + "integrity": "sha512-Sb487aTOCr9drQVL8pIxOzVhafOjZN9UU54hiN8PU3uAiSV7lx1yYNpbNmex2PK6dSJoNTSJUUswT651yww3Mg==" + }, "node_modules/loose-envify": { "version": "1.4.0", "resolved": "https://registry.npmjs.org/loose-envify/-/loose-envify-1.4.0.tgz", @@ -3019,7 +3138,6 @@ "version": "6.0.0", "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz", "integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==", - "dev": true, "dependencies": { "yallist": "^4.0.0" }, @@ -3101,8 +3219,7 @@ "node_modules/ms": { "version": "2.1.2", "resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz", - "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==", - "dev": true + "integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==" }, "node_modules/mz": { "version": "2.7.0", @@ -4010,6 +4127,25 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/safe-buffer": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz", + "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==", + "funding": [ + { + "type": "github", + "url": "https://github.com/sponsors/feross" + }, + { + "type": "patreon", + "url": "https://www.patreon.com/feross" + }, + { + "type": "consulting", + "url": "https://feross.org/support" + } + ] + }, "node_modules/safe-regex-test": { "version": "1.0.0", "resolved": "https://registry.npmjs.org/safe-regex-test/-/safe-regex-test-1.0.0.tgz", @@ -4036,7 +4172,6 @@ "version": "7.5.4", "resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz", "integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==", - "dev": true, "dependencies": { "lru-cache": "^6.0.0" }, @@ -4700,8 +4835,7 @@ "node_modules/undici-types": { "version": "5.26.5", "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz", - "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==", - "dev": true + "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==" }, "node_modules/update-browserslist-db": { "version": "1.0.13", @@ -4962,8 +5096,7 @@ "node_modules/yallist": { "version": "4.0.0", "resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz", - "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==", - "dev": true + "integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==" }, "node_modules/yaml": { "version": "2.3.4", diff --git a/weatherfit_refactoring/package.json b/weatherfit_refactoring/package.json index 74dddee..dba5090 100644 --- a/weatherfit_refactoring/package.json +++ b/weatherfit_refactoring/package.json @@ -10,8 +10,11 @@ "format": "prettier --write \"**/*.{js,jsx,ts,tsx,json,css,scss,md}\"" }, "dependencies": { + "@types/jsonwebtoken": "^9.0.6", "axios": "^1.6.7", + "dompurify": "^3.0.11", "js-cookie": "^3.0.5", + "jsonwebtoken": "^9.0.2", "next": "14.0.4", "react": "^18", "react-dom": "^18", @@ -21,6 +24,7 @@ "zustand": "^4.4.7" }, "devDependencies": { + "@types/dompurify": "^3.0.5", "@types/js-cookie": "^3.0.6", "@types/node": "^20", "@types/react": "^18", diff --git a/weatherfit_refactoring/public/images/question.bmp b/weatherfit_refactoring/public/images/question.bmp new file mode 100644 index 0000000..9c59ed9 Binary files /dev/null and b/weatherfit_refactoring/public/images/question.bmp differ diff --git a/weatherfit_refactoring/src/Components/Atoms/Button/ButtonStore.tsx b/weatherfit_refactoring/src/Components/Atoms/Button/ButtonStore.tsx index 80729aa..a4e42fa 100644 --- a/weatherfit_refactoring/src/Components/Atoms/Button/ButtonStore.tsx +++ b/weatherfit_refactoring/src/Components/Atoms/Button/ButtonStore.tsx @@ -75,7 +75,7 @@ export default function ButtonStore({ case ButtonStyle.CATEGORY_BTN_Y: return ( diff --git a/weatherfit_refactoring/src/Components/Molecules/BestThreeCodi.tsx b/weatherfit_refactoring/src/Components/Molecules/BestThreeCodi.tsx index 4c62309..f41fe19 100644 --- a/weatherfit_refactoring/src/Components/Molecules/BestThreeCodi.tsx +++ b/weatherfit_refactoring/src/Components/Molecules/BestThreeCodi.tsx @@ -4,11 +4,23 @@ import Image from 'next/image' export default function BestThreeCodi({ data }: { data?: FEEDDATA_detail }) { if (!data || !data.images) { - return null + return ( +
+ + {`없을 + +
+ ) } return ( - <> +
{data.images.map((image, index) => ( @@ -23,6 +35,6 @@ export default function BestThreeCodi({ data }: { data?: FEEDDATA_detail }) { // 유저 정보 넣어야 함 ))} - +
) } diff --git a/weatherfit_refactoring/src/Components/Molecules/DetailCategory.tsx b/weatherfit_refactoring/src/Components/Molecules/DetailCategory.tsx index 77ae3df..6307880 100644 --- a/weatherfit_refactoring/src/Components/Molecules/DetailCategory.tsx +++ b/weatherfit_refactoring/src/Components/Molecules/DetailCategory.tsx @@ -71,6 +71,7 @@ export default function DetailCategory({ ) } + function setFeedData(toJson: any) { throw new Error('Function not implemented.') } diff --git a/weatherfit_refactoring/src/Components/Molecules/DetailContent.tsx b/weatherfit_refactoring/src/Components/Molecules/DetailContent.tsx index db97da5..4b54a71 100644 --- a/weatherfit_refactoring/src/Components/Molecules/DetailContent.tsx +++ b/weatherfit_refactoring/src/Components/Molecules/DetailContent.tsx @@ -1,4 +1,5 @@ 'use client' +import DOMPurify from 'dompurify' import { FeedData } from '@/Store/FeedData' import { useRouter } from 'next/navigation' @@ -37,27 +38,28 @@ export default function DetailContent({ const result: JSX.Element[] = [] splitContent.forEach((current, index) => { - const replacedContent = current + const cleanedContent = DOMPurify.sanitize(current) .replace(/\n/g, '
') .replace(/ /g, ' ') result.push( , ) if (index !== splitContent.length - 1) { const currentHashTag = matchedHashTags[index] - const tagIndex = hashTag.indexOf(currentHashTag.slice(1)) + const cleanedHashTag = DOMPurify.sanitize(currentHashTag) + const tagIndex = hashTag.indexOf(cleanedHashTag.slice(1)) result.push( handleHashTagClick(currentHashTag)}> - {currentHashTag} + onClick={() => handleHashTagClick(cleanedHashTag)}> + {cleanedHashTag} , ) } @@ -68,7 +70,6 @@ export default function DetailContent({ return (
- {/* 추후에 더보기 접기 버튼 넣어야 할 듯 */} {nickName} {extractAndStyleHashtags(content)}
diff --git a/weatherfit_refactoring/src/Components/Molecules/DetailEtc.tsx b/weatherfit_refactoring/src/Components/Molecules/DetailEtc.tsx index 1421ebc..fd40568 100644 --- a/weatherfit_refactoring/src/Components/Molecules/DetailEtc.tsx +++ b/weatherfit_refactoring/src/Components/Molecules/DetailEtc.tsx @@ -1,15 +1,29 @@ 'use client' import { useState } from 'react' +import jwt from 'jsonwebtoken' import IconStore, { IconStyle } from '../Atoms/Icon/IconStore' import ButtonStore, { ButtonStyle } from '../Atoms/Button/ButtonStore' import { usePathname, useRouter } from 'next/navigation' import { deleteAlert, deleteOkAlert } from '@/utils/function/utilFunction' +import { AuthTokenStore } from '@/Store/AuthToken' -export default function DetailEtc(boardId: BOARDID) { +export default function DetailEtc({ + boardId, + nickName, +}: { + boardId: BOARDID + nickName: string +}) { const [isDropdownOpen, setIsDropdownOpen] = useState(false) + const { accesstoken } = AuthTokenStore() + const decodedToken = accesstoken + ? (jwt.decode(accesstoken) as { [key: string]: any }) + : null + const decoded_nickName = decodedToken?.sub const router = useRouter() const currentUrl = usePathname() + const handleEdit = () => { router.push(`${currentUrl}/edit`) } @@ -23,9 +37,7 @@ export default function DetailEtc(boardId: BOARDID) { { method: 'DELETE', headers: { - // Authorization: 'Bearer ' + logintoken, - Authorization: - 'Bearer eyJhbGciOiJIUzI1NiJ9.eyJpYXQiOjE3MDY3OTA5MDEsImV4cCI6MTcwNjgwMTcwMSwic3ViIjoi7YWM7Iqk7YSwNTUifQ.sdm2nHun06cOIeWzXFv8xSbuuhY_yCsiRT7Upu1vtIs', + Authorization: 'Bearer ' + accesstoken, }, }, ) @@ -45,12 +57,15 @@ export default function DetailEtc(boardId: BOARDID) { return ( <> - setIsDropdownOpen(!isDropdownOpen)} - /> + {' '} + {decoded_nickName === nickName ? ( + setIsDropdownOpen(!isDropdownOpen)} + /> + ) : null} {isDropdownOpen && (
+ onClickFunction={() => onClickFunction}> {btnText} ) : iconStyleCase ? ( diff --git a/weatherfit_refactoring/src/Components/Molecules/LikeAndComment.tsx b/weatherfit_refactoring/src/Components/Molecules/LikeAndComment.tsx index 9844fbf..2b524bc 100644 --- a/weatherfit_refactoring/src/Components/Molecules/LikeAndComment.tsx +++ b/weatherfit_refactoring/src/Components/Molecules/LikeAndComment.tsx @@ -1,10 +1,42 @@ +'use client' + +import { useStore } from '@/Store/Store' import IconStore, { IconStyle } from '../Atoms/Icon/IconStore' import CommentIcon from './CommentIcon' +import { AuthTokenStore } from '@/Store/AuthToken' + +export default function LikeAndComment({ boardId }: { boardId: BOARDID }) { + const { isLiked, toggleLikeState } = useStore() + const { accesstoken } = AuthTokenStore() + + const toggleLike = async () => { + try { + const response = await fetch( + `https://www.yourwebsite.com/board/like/${boardId}`, + { + method: 'POST', + headers: { + Authorization: 'Bearer ' + accesstoken, + }, + }, + ) + if (!response.ok) { + throw new Error('Network response was not ok.') + } + toggleLikeState() + } catch (error) { + console.error('좋아요 실패:', error) + } + } -export default function LikeAndComment() { return (
- +
+ +
) diff --git a/weatherfit_refactoring/src/Components/Molecules/TextAreaMolecule.tsx b/weatherfit_refactoring/src/Components/Molecules/TextAreaMolecule.tsx index d5e1a02..f83ba8e 100644 --- a/weatherfit_refactoring/src/Components/Molecules/TextAreaMolecule.tsx +++ b/weatherfit_refactoring/src/Components/Molecules/TextAreaMolecule.tsx @@ -7,17 +7,24 @@ import { extractHashtags } from '@/utils/function/utilFunction' export default function TextAreaMolecule({ initContent, + mode, }: { initContent?: FEEDDATA_detail['content'] + mode: 'edit' | 'upload' }) { const { content, setContent, setHashTag } = useStore() const textAreaRef = useRef(null) useEffect(() => { - if (initContent) { + // Edit 모드일 때는 initContent로 초기화 + if (mode === 'edit' && initContent) { setContent(initContent) } - }, [setContent]) + // Upload 모드일 때는 내용을 비워준다 + if (mode === 'upload') { + setContent('') + } + }, [initContent, mode, setContent]) const handleChange = () => { if (textAreaRef.current) { diff --git a/weatherfit_refactoring/src/Components/Organisms/DetailOrganism.tsx b/weatherfit_refactoring/src/Components/Organisms/DetailOrganism.tsx index 09e063d..4d3ef2e 100644 --- a/weatherfit_refactoring/src/Components/Organisms/DetailOrganism.tsx +++ b/weatherfit_refactoring/src/Components/Organisms/DetailOrganism.tsx @@ -1,12 +1,16 @@ import DetailContent from '@/Components/Molecules/DetailContent' -import DetailImage from '@/Components/Molecules/DetailImge' +import DetailImage from '@/Components/Molecules/DetailImage' import DetailCategory from '../Molecules/DetailCategory' import LikeAndComment from '../Molecules/LikeAndComment' import DetailProfile from '../Molecules/DetailProfile' import DetailEtc from '../Molecules/DetailEtc' import NotFound from '@/app/not-found' -export default async function DetailOrganism({ boardId }: BOARDID) { +export default async function DetailOrganism({ + boardId, +}: { + boardId: BOARDID +}) { const fetchBoardDataResponse = await fetch( `https://www.jerneithe.site/board/detail/${boardId}`, { @@ -39,10 +43,10 @@ export default async function DetailOrganism({ boardId }: BOARDID) { nickName={fetchBoardData.nickName} userData={fetchUserData} /> - +
- + { + if (selectedImages.length === 0) { + alert('업로드 된 사진이 없습니다.') + return // 함수를 여기서 종료하여 더 이상 진행하지 않습니다. + } + + if (category.length === 0) { + alert('선택된 카테고리가 없습니다.') + return // 함수를 여기서 종료합니다. + } + try { const formData = new FormData() const boardData = { @@ -36,18 +48,17 @@ export default function EditHeader(boardId: BOARDID) { body: formData, headers: { 'Content-Type': 'multipart/form-data', - // Authorization: 'Bearer ' + accessToken, + Authorization: 'Bearer ' + accesstoken, }, }, ) - console.log(response) - console.log('수정 버튼 클릭') - console.log('content: ', content) - console.log('hashTag: ', hashTag) - const images = formData.getAll('images') - console.log('images: ', images) - console.log('category', category) + if (response.ok) { + alert('수정이 완료되었습니다.') + window.location.href = `/detail/${boardId}` + } else { + alert('수정에 실패했습니다. 다시 시도해주세요.') + } } catch (error) { console.error(error) } diff --git a/weatherfit_refactoring/src/Components/Organisms/EditOrganism.tsx b/weatherfit_refactoring/src/Components/Organisms/EditOrganism.tsx index a87eb71..fbbfe5b 100644 --- a/weatherfit_refactoring/src/Components/Organisms/EditOrganism.tsx +++ b/weatherfit_refactoring/src/Components/Organisms/EditOrganism.tsx @@ -19,11 +19,11 @@ export default async function EditOrganism({ boardId }: BOARDID) {
- +
- +
- +
) diff --git a/weatherfit_refactoring/src/Components/Organisms/ImageUpload.tsx b/weatherfit_refactoring/src/Components/Organisms/ImageUpload.tsx index 78c0c22..ad324de 100644 --- a/weatherfit_refactoring/src/Components/Organisms/ImageUpload.tsx +++ b/weatherfit_refactoring/src/Components/Organisms/ImageUpload.tsx @@ -7,8 +7,10 @@ import ArrayImage from '../Molecules/ArrayImage' export default function ImageUpload({ images, + mode, }: { images?: FEEDDATA_detail['images'] + mode: 'edit' | 'upload' }) { const { selectedImages, @@ -17,14 +19,16 @@ export default function ImageUpload({ setExistingImages, setDeletedImages, } = useStore() - // const [existingImages, setExistingImages] = useState([]) - const initialImages = images useEffect(() => { - if (initialImages) { - setExistingImages(initialImages) + if (mode === 'edit' && images) { + setExistingImages(images) + } else if (mode === 'upload') { + // Upload 모드에서는 선택된 이미지와 기존 이미지 모두 초기화 + setSelectedImages([]) + setExistingImages([]) } - }, [initialImages]) + }, [mode, images, setExistingImages, setSelectedImages]) const handleImagesSelected = useCallback((files: File[] | null) => { setSelectedImages(files ? Array.from(files) : []) diff --git a/weatherfit_refactoring/src/Components/Organisms/SelectCategory.tsx b/weatherfit_refactoring/src/Components/Organisms/SelectCategory.tsx index d58fca8..2e73e3a 100644 --- a/weatherfit_refactoring/src/Components/Organisms/SelectCategory.tsx +++ b/weatherfit_refactoring/src/Components/Organisms/SelectCategory.tsx @@ -7,8 +7,10 @@ import { useStore } from '../../Store/Store' export default function SelectCategory({ initCategory, + mode, }: { initCategory?: FEEDDATA_detail['category'] + mode: 'edit' | 'upload' }) { const { setSelectedSubCategories } = useStore() @@ -26,7 +28,9 @@ export default function SelectCategory({ key={category} category={category} subCategories={subCategories} - initialSelectedSubCategories={initCategory} + initialSelectedSubCategories={ + mode === 'edit' ? initCategory : undefined + } onSelect={selectedSubCategories => handleCategorySelect(category, selectedSubCategories) } diff --git a/weatherfit_refactoring/src/Components/Organisms/UploadHeader.tsx b/weatherfit_refactoring/src/Components/Organisms/UploadHeader.tsx index d13643c..c19ce69 100644 --- a/weatherfit_refactoring/src/Components/Organisms/UploadHeader.tsx +++ b/weatherfit_refactoring/src/Components/Organisms/UploadHeader.tsx @@ -3,14 +3,26 @@ import Header from '../Molecules/Header' import { useStore } from '../../Store/Store' import { WeatherIcon } from '@/Store/WeatherIcon' import { WeatherTemp } from '@/Store/WeatherTemp' +import { AuthTokenStore } from '@/Store/AuthToken' export default function UploadHeader() { const { content, hashTag, selectedImages, selectedSubCategories } = useStore() const category = Object.values(selectedSubCategories).flat() // 하위 카테고리들만 저장 const { weatherIcon } = WeatherIcon() const { temperature } = WeatherTemp() + const { accesstoken } = AuthTokenStore() const handleOnClick = async () => { + if (selectedImages.length === 0) { + alert('업로드 된 사진이 없습니다.') + return // 함수를 여기서 종료하여 더 이상 진행하지 않습니다. + } + + if (category.length === 0) { + alert('선택된 카테고리가 없습니다.') + return // 함수를 여기서 종료합니다. + } + try { const formData = new FormData() const boardData = { @@ -31,17 +43,16 @@ export default function UploadHeader() { body: formData, headers: { 'Content-Type': 'multipart/form-data', - // Authorization: 'Bearer ' + accessToken, + Authorization: 'Bearer ' + accesstoken, }, }) - console.log(response) - console.log('등록 버튼 클릭') - console.log('content: ', content) //ok - console.log('hashTag: ', hashTag) //ok - const images = formData.getAll('images') - console.log('images: ', images) - console.log('selected categories', category) + if (response.ok) { + alert('업로드 되었습니다.') + window.location.href = `/feed` + } else { + alert('업로드에 실패했습니다. 다시 시도해주세요.') + } } catch (error) { console.error(error) } diff --git a/weatherfit_refactoring/src/Store/Store.ts b/weatherfit_refactoring/src/Store/Store.ts index bc5eb1b..958d32c 100644 --- a/weatherfit_refactoring/src/Store/Store.ts +++ b/weatherfit_refactoring/src/Store/Store.ts @@ -15,6 +15,9 @@ interface State { setInitialSubCategories: (initialSubCategories: string[]) => void deletedImages: number[] setDeletedImages: (imageId: number) => void + // 좋아요 + isLiked: boolean + toggleLikeState: () => void } export const useStore = create(set => ({ @@ -50,4 +53,6 @@ export const useStore = create(set => ({ deletedImages: [...state.deletedImages, imageId], })) }, + isLiked: false, + toggleLikeState: () => set(state => ({ isLiked: !state.isLiked })), })) diff --git a/weatherfit_refactoring/src/app/detail/[id]/page.tsx b/weatherfit_refactoring/src/app/detail/[id]/page.tsx index 7aadf0c..230a672 100644 --- a/weatherfit_refactoring/src/app/detail/[id]/page.tsx +++ b/weatherfit_refactoring/src/app/detail/[id]/page.tsx @@ -2,7 +2,7 @@ import Header from '@/Components/Molecules/Header' import WeatherNavbar from '@/Components/Molecules/WeatherNavbar' import DetailOrganism from '@/Components/Organisms/DetailOrganism' -export default function Detail({ params }: { params: { id: string } }) { +export default function Detail({ params }: { params: { id: BOARDID } }) { const { id: boardId } = params return ( diff --git a/weatherfit_refactoring/src/app/upload/page.tsx b/weatherfit_refactoring/src/app/upload/page.tsx index 3403538..fd1f5ae 100644 --- a/weatherfit_refactoring/src/app/upload/page.tsx +++ b/weatherfit_refactoring/src/app/upload/page.tsx @@ -5,20 +5,48 @@ import TextAreaMolecule from '@/Components/Molecules/TextAreaMolecule' import SelectCategory from '@/Components/Organisms/SelectCategory' import UploadHeader from '@/Components/Organisms/UploadHeader' import UploadWeather from '@/Components/Molecules/UploadWeather' +import Loading from '@/Components/Organisms/Loading' +import NoLogin from '@/Components/Organisms/NoLogin' +import { LoadingStore } from '@/Store/Loading' +import { CheckStore } from '@/Store/Check' +import { AuthTokenStore } from '@/Store/AuthToken' +import { loginCheck } from '@/utils/function/utilFunction' +import { useEffect } from 'react' export default function Upload() { + const { loading, setLoading } = LoadingStore() + const { accesstoken, setAccessToken } = AuthTokenStore() + const { check, setCheck } = CheckStore() + + useEffect(() => { + setAccessToken() + loginCheck(accesstoken, setCheck, setLoading) + }, [accesstoken]) + return ( -
- -
-
- - -
- -
- -
-
+ <> + {loading ? ( + + ) : ( + <> + {check ? ( +
+ +
+
+ + +
+ +
+ +
+
+ ) : ( + + )} + + )} + ) }