diff --git a/weatherfit_refactoring/package-lock.json b/weatherfit_refactoring/package-lock.json index b0c0160..c8a301e 100644 --- a/weatherfit_refactoring/package-lock.json +++ b/weatherfit_refactoring/package-lock.json @@ -8,6 +8,7 @@ "name": "weatherfit_refectoring", "version": "0.1.0", "dependencies": { + "axios": "^1.6.5", "next": "14.0.4", "react": "^18", "react-dom": "^18", @@ -875,6 +876,11 @@ "has-symbols": "^1.0.3" } }, + "node_modules/asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha512-Oei9OH4tRh0YqU3GxhX79dM/mwVgvbZJaSNaRk+bshkj0S5cfHcgYakreBjrHwatXKbz+IoIdYLxrKim2MjW0Q==" + }, "node_modules/autoprefixer": { "version": "10.4.16", "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-10.4.16.tgz", @@ -933,6 +939,16 @@ "node": ">=4" } }, + "node_modules/axios": { + "version": "1.6.5", + "resolved": "https://registry.npmjs.org/axios/-/axios-1.6.5.tgz", + "integrity": "sha512-Ii012v05KEVuUoFWmMW/UQv9aRIc3ZwkWDcM+h5Il8izZCtRVpDUfwpoFf7eOtajT3QiGR4yDUx7lPqHJULgbg==", + "dependencies": { + "follow-redirects": "^1.15.4", + "form-data": "^4.0.0", + "proxy-from-env": "^1.1.0" + } + }, "node_modules/axobject-query": { "version": "3.2.1", "resolved": "https://registry.npmjs.org/axobject-query/-/axobject-query-3.2.1.tgz", @@ -1151,6 +1167,17 @@ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==", "dev": true }, + "node_modules/combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dependencies": { + "delayed-stream": "~1.0.0" + }, + "engines": { + "node": ">= 0.8" + } + }, "node_modules/commander": { "version": "4.1.1", "resolved": "https://registry.npmjs.org/commander/-/commander-4.1.1.tgz", @@ -1258,6 +1285,14 @@ "url": "https://github.com/sponsors/ljharb" } }, + "node_modules/delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha512-ZySD7Nf91aLB0RxL4KGrKHBXl7Eds1DAmEdcoVawXnLD7SDhpNgtuII2aAkg7a7QS41jxPSZ17p4VdGnMHk3MQ==", + "engines": { + "node": ">=0.4.0" + } + }, "node_modules/dequal": { "version": "2.0.3", "resolved": "https://registry.npmjs.org/dequal/-/dequal-2.0.3.tgz", @@ -1995,6 +2030,25 @@ "integrity": "sha512-36yxDn5H7OFZQla0/jFJmbIKTdZAQHngCedGxiMmpNfEZM0sdEeT+WczLQrjK6D7o2aiyLYDnkw0R3JK0Qv1RQ==", "dev": true }, + "node_modules/follow-redirects": { + "version": "1.15.5", + "resolved": "https://registry.npmjs.org/follow-redirects/-/follow-redirects-1.15.5.tgz", + "integrity": "sha512-vSFWUON1B+yAw1VN4xMfxgn5fTUiaOzAJCKBwIIgT/+7CuGy9+r+5gITvP62j3RmaD5Ph65UaERdOSRGUzZtgw==", + "funding": [ + { + "type": "individual", + "url": "https://github.com/sponsors/RubenVerborgh" + } + ], + "engines": { + "node": ">=4.0" + }, + "peerDependenciesMeta": { + "debug": { + "optional": true + } + } + }, "node_modules/for-each": { "version": "0.3.3", "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz", @@ -2020,6 +2074,19 @@ "url": "https://github.com/sponsors/isaacs" } }, + "node_modules/form-data": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-4.0.0.tgz", + "integrity": "sha512-ETEklSGi5t0QMZuiXoA/Q6vcnxcLQP5vdugSpuAyi6SVGi2clPPp+xgEhuMaHC+zGgn31Kd235W35f7Hykkaww==", + "dependencies": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.8", + "mime-types": "^2.1.12" + }, + "engines": { + "node": ">= 6" + } + }, "node_modules/fraction.js": { "version": "4.3.7", "resolved": "https://registry.npmjs.org/fraction.js/-/fraction.js-4.3.7.tgz", @@ -2957,6 +3024,25 @@ "node": ">=8.6" } }, + "node_modules/mime-db": { + "version": "1.52.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.52.0.tgz", + "integrity": "sha512-sPU4uV7dYlvtWJxwwxHD0PuihVNiE7TyAbQ5SWxDCB9mUYvOgroQOwYQQOKPJ8CIbE+1ETVlOoK1UC2nU3gYvg==", + "engines": { + "node": ">= 0.6" + } + }, + "node_modules/mime-types": { + "version": "2.1.35", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.35.tgz", + "integrity": "sha512-ZDY+bPm5zTTF+YpCrAU9nK0UgICYPT0QtT1NZWFv4s++TNkcgVaT0g6+4R2uI4MjQjzysHB1zxuWL50hzaeXiw==", + "dependencies": { + "mime-db": "1.52.0" + }, + "engines": { + "node": ">= 0.6" + } + }, "node_modules/minimatch": { "version": "3.1.2", "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz", @@ -3671,6 +3757,11 @@ "react-is": "^16.13.1" } }, + "node_modules/proxy-from-env": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/proxy-from-env/-/proxy-from-env-1.1.0.tgz", + "integrity": "sha512-D+zkORCbA9f1tdWRK0RaCR3GPv50cMxcrz4X8k5LTSUD1Dkw47mKJEZQNunItRTkWwgtaUSo1RVFRIG9ZXiFYg==" + }, "node_modules/punycode": { "version": "2.3.1", "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.3.1.tgz", diff --git a/weatherfit_refactoring/package.json b/weatherfit_refactoring/package.json index 8acaf8a..f1a49dc 100644 --- a/weatherfit_refactoring/package.json +++ b/weatherfit_refactoring/package.json @@ -10,6 +10,7 @@ "format": "prettier --write \"**/*.{js,jsx,ts,tsx,json,css,scss,md}\"" }, "dependencies": { + "axios": "^1.6.5", "next": "14.0.4", "react": "^18", "react-dom": "^18", diff --git a/weatherfit_refactoring/src/Components/Molecules/Logout.tsx b/weatherfit_refactoring/src/Components/Molecules/Logout.tsx new file mode 100644 index 0000000..b883d33 --- /dev/null +++ b/weatherfit_refactoring/src/Components/Molecules/Logout.tsx @@ -0,0 +1,22 @@ +export default function Logout() { + const handleLogout = () => { + if (confirm('로그아웃 하시겠습니까?')) { + // 쿠키에 로그인 토큰 삭제 + // console.log("로그아웃 후 쿠키 확인: ", accessToken); + console.log('로그아웃 후 쿠키 확인: ') + alert('로그아웃 되었습니다.') + window.location.href = '/' + } + } + + return ( + <> + + + ) +} diff --git a/weatherfit_refactoring/src/Components/Molecules/PostCount.tsx b/weatherfit_refactoring/src/Components/Molecules/PostCount.tsx new file mode 100644 index 0000000..f2585c0 --- /dev/null +++ b/weatherfit_refactoring/src/Components/Molecules/PostCount.tsx @@ -0,0 +1,13 @@ +interface Props { + title: string + count: number +} + +export default function PostCount({ title, count }: Props) { + return ( +
+

{title}

+

{count}

+
+ ) +} diff --git a/weatherfit_refactoring/src/Components/Molecules/ProfileImageEdit.tsx b/weatherfit_refactoring/src/Components/Molecules/ProfileImageEdit.tsx new file mode 100644 index 0000000..a591b45 --- /dev/null +++ b/weatherfit_refactoring/src/Components/Molecules/ProfileImageEdit.tsx @@ -0,0 +1,103 @@ +'use client' + +import React, { useState } from 'react' +import IconStore, { IconStyle } from '../Atoms/Icon/IconStore' +import Image from 'next/image' +import axios from 'axios' + +export default function ProfileImageEdit() { + // const [selectedImage, setSelectedImage] = useState(userProfileImage) + const [selectedImage, setSelectedImage] = useState(null) + + // 파일 비동기 전송 + // const handleImageSubmit = async () => { + // try { + // if (confirm('이미지를 수정하시겠습니까?')) { + // const formData = new FormData() + // if (selectedImage) { + // formData.append('image', selectedImage) // 이미지 파일을 FormData에 추가 + // } + + // formData.append('email', email) + + // for (let [key, value] of formData.entries()) { + // console.log(`${key}: ${value}`) + // } + + // const response = await axios.patch( + // `https://www.jerneithe.site/user/api/profile/modify/image`, + // formData, + // { + // headers: { + // 'Content-Type': 'multipart/form-data', + // }, + // }, + // ) + + // console.log('이미지 수정 Data:', response.data) + + // // 모달 닫히는 함수 실행하기 + // } + // } catch (error) { + // console.error('이미지 업로드 에러: ', error) + // } + // } + + const handleImageUpload = (e: any) => { + const file = e.target.files[0] + setSelectedImage(file) + } + + const handleDefaultImage = ( + e: React.MouseEvent, + ) => { + e.preventDefault() + setSelectedImage(null) // 기본 이미지로 설정하면 userProfileImage가 null로 변경 + } + + return ( + <> +
+ {selectedImage ? ( + typeof selectedImage === 'string' ? ( + Current + ) : ( + Uploaded + ) + ) : ( + + )} +
+ {/* 파일 업로드 인풋 */} +
+ + + | + +
+ + + ) +} diff --git a/weatherfit_refactoring/src/Components/Molecules/Unregister.tsx b/weatherfit_refactoring/src/Components/Molecules/Unregister.tsx new file mode 100644 index 0000000..acba27f --- /dev/null +++ b/weatherfit_refactoring/src/Components/Molecules/Unregister.tsx @@ -0,0 +1,36 @@ +import axios from 'axios' + +// Props로 UserInfo에서 email 있어야 함 + +export default function Unregister() { + const handleUnregister = async () => { + try { + if (confirm('정말로 탈퇴하시겠습니까?')) { + const response = await axios({ + method: 'DELETE', + // url: `https://www.jerneithe.site/user/api/profile/remove/${email}`, + headers: { + Authorization: 'Bearer ', + }, + }) + console.log('회원 탈퇴 response: ', response) + // 쿠키에 로그인 토큰 삭제 + alert('그동안 옷늘날씨를 이용해 주셔서 감사합니다.') + window.location.href = '/' + } + } catch (error) { + console.log('회원 탈퇴 err: ', error) + } + } + + return ( + <> + + + ) +} diff --git a/weatherfit_refactoring/src/Components/Organisms/ProfileBoard.tsx b/weatherfit_refactoring/src/Components/Organisms/ProfileBoard.tsx index e00394f..97e1885 100644 --- a/weatherfit_refactoring/src/Components/Organisms/ProfileBoard.tsx +++ b/weatherfit_refactoring/src/Components/Organisms/ProfileBoard.tsx @@ -1,13 +1,53 @@ +'use client' + import React, { useState } from 'react' import ProfilePostBar from '../Molecules/ProfilePostBar' +import ProfilePost from '../Molecules/ProfilePost' + +interface IMAGE { + boardId: number + imageId: number + imageUrl: string +} + +interface LIKE { + likeId: number + nickName: string +} +interface FEEDATA { + boardId: number + images: IMAGE + likeCount: number + likelist: LIKE[] + nickName: string + temperature: number + weather: string + weatherIcon?: string +} + +interface Props { + myPost: FEEDATA[] + myLikePost: FEEDATA[] +} + +export default function ProfileBoard({ myPost, myLikePost }: Props) { + const [isFeedSelected, setIsFeedSelected] = useState(true) + + const handleFeedClick = () => { + setIsFeedSelected(true) + } -export default function ProfileBoard() { - // 여기서 게시물 수 불러오기 + const handleLikeClick = () => { + setIsFeedSelected(false) + } return ( <> - - + + ) } diff --git a/weatherfit_refactoring/src/Components/Organisms/ProfileEditModal.tsx b/weatherfit_refactoring/src/Components/Organisms/ProfileEditModal.tsx index efbe3dd..0e353f3 100644 --- a/weatherfit_refactoring/src/Components/Organisms/ProfileEditModal.tsx +++ b/weatherfit_refactoring/src/Components/Organisms/ProfileEditModal.tsx @@ -5,6 +5,9 @@ import BoxStore, { BoxStyle } from '../Atoms/Box/BoxStore' import InputStore, { InputStyle } from '../Atoms/Input/InputStore' import ButtonStore, { ButtonStyle } from '@/Components/Atoms/Button/ButtonStore' import ProfileModalInfo from '../Molecules/ProfileModalInfo' +import Logout from '../Molecules/Logout' +import Unregister from '../Molecules/Unregister' +import ProfileImageEdit from '../Molecules/ProfileImageEdit' interface Props { onClickFunction?: () => void @@ -29,18 +32,19 @@ export default function ProfileEditModal({ onClickFunction }: Props) {
+
{/* 이메일, 이름, 닉네임 부분 */} -
+

{/* 비밀번호 부분 */} -
-
-

+ +

+

비밀번호 (8~20자 영문, 숫자, 특수기호 조합)

@@ -70,6 +74,11 @@ export default function ProfileEditModal({ onClickFunction }: Props) { 수정 +
+
+ + +
diff --git a/weatherfit_refactoring/src/Components/Organisms/ProfileHeader.tsx b/weatherfit_refactoring/src/Components/Organisms/ProfileHeader.tsx index 8d6e98e..226aa84 100644 --- a/weatherfit_refactoring/src/Components/Organisms/ProfileHeader.tsx +++ b/weatherfit_refactoring/src/Components/Organisms/ProfileHeader.tsx @@ -2,6 +2,9 @@ import React, { useState, MouseEventHandler } from 'react' import { ButtonStyle } from '../Atoms/Button/ButtonStore' +import ProfileEditModal from './ProfileEditModal' +import Header from '../Molecules/Header' +import { IconStyle } from '../Atoms/Icon/IconStore' export default function ProfileHeader() { const [isModalOpen, setIsModalOpen] = useState(false) diff --git a/weatherfit_refactoring/src/Components/molecules/ProfileInfo.tsx b/weatherfit_refactoring/src/Components/molecules/ProfileInfo.tsx index f413be7..5927b99 100644 --- a/weatherfit_refactoring/src/Components/molecules/ProfileInfo.tsx +++ b/weatherfit_refactoring/src/Components/molecules/ProfileInfo.tsx @@ -1,18 +1,66 @@ -export default function ProfileInfo() { +import PostCount from './PostCount' + +interface IMAGE { + boardId: number + imageId: number + imageUrl: string +} + +interface LIKE { + likeId: number + nickName: string +} +interface FEEDATA { + boardId: number + images: IMAGE + likeCount: number + likelist: LIKE[] + nickName: string + temperature: number + weather: string + weatherIcon?: string +} + +interface UserData { + nickname: string + name: string + email: string + pw: string +} + +interface Props { + profileImage: string | null + userInfo: UserData + myPost: FEEDATA[] + myLikePost: FEEDATA[] +} + +export default function ProfileInfo({ + profileImage, + userInfo, + myPost, + myLikePost, +}: Props) { return (

깜찍이

+ {/*
+

{userInfo.nickname}

*/}
+ {/* -------------------------------지우기 */}

내 게시물

-

23

+

{myPost.length}

좋아요 한 게시물

-

147

+

{myLikePost.length}

+ {/* -------------------------------------- */} + {/* + */}
) } diff --git a/weatherfit_refactoring/src/Components/molecules/ProfilePost.tsx b/weatherfit_refactoring/src/Components/molecules/ProfilePost.tsx index 886ae94..6608577 100644 --- a/weatherfit_refactoring/src/Components/molecules/ProfilePost.tsx +++ b/weatherfit_refactoring/src/Components/molecules/ProfilePost.tsx @@ -1,13 +1,51 @@ -export default function ProfilePost() { +import Image from 'next/image' + +interface IMAGE { + boardId: number + imageId: number + imageUrl: string +} + +interface LIKE { + likeId: number + nickName: string +} +interface FEEDATA { + boardId: number + images: IMAGE + likeCount: number + likelist: LIKE[] + nickName: string + temperature: number + weather: string + weatherIcon?: string +} + +interface Props { + postData: FEEDATA[] +} + +export default function ProfilePost({ postData }: Props) { return (
- {/*
*/} -
-
-
-
-
-
+ {/* {postData.length > 0 ? ( + postData.map(item => ( +
+ {item.images && ( + 게시물 이미지 + )} +
+ )) + ) : ( + <> +

게시물을 등록해주세요.

+ + )} */}
) diff --git a/weatherfit_refactoring/src/Components/molecules/ProfilePostBar.tsx b/weatherfit_refactoring/src/Components/molecules/ProfilePostBar.tsx index 413a104..4567c3d 100644 --- a/weatherfit_refactoring/src/Components/molecules/ProfilePostBar.tsx +++ b/weatherfit_refactoring/src/Components/molecules/ProfilePostBar.tsx @@ -1,10 +1,19 @@ 'use client' -import { useState } from 'react' +import { useEffect, useState } from 'react' import ButtonStore, { ButtonStyle } from '../Atoms/Button/ButtonStore' -export default function ProfilePostBar() { +interface Props { + onFeedClick: () => void + onLikeClick: () => void +} + +export default function ProfilePostBar({ onFeedClick, onLikeClick }: Props) { const [isFeedSelected, setIsFeedSelected] = useState(true) + useEffect(() => { + isFeedSelected ? onFeedClick() : onLikeClick() + }, [isFeedSelected]) + const handleFeedClike = () => { setIsFeedSelected(true) } diff --git a/weatherfit_refactoring/src/app/mypage/page.tsx b/weatherfit_refactoring/src/app/mypage/page.tsx index b8f0617..880c92c 100644 --- a/weatherfit_refactoring/src/app/mypage/page.tsx +++ b/weatherfit_refactoring/src/app/mypage/page.tsx @@ -1,17 +1,93 @@ -// "use client" +'use client' +import React, { useEffect, useState } from 'react' +import axios from 'axios' import ProfileInfo from '@/Components/Molecules/ProfileInfo' -import ProfilePost from '@/Components/Molecules/ProfilePost' -import ProfilePostBar from '@/Components/Molecules/ProfilePostBar' import ProfileHeader from '@/Components/Organisms/ProfileHeader' +import ProfileBoard from '@/Components/Organisms/ProfileBoard' + +interface IMAGE { + boardId: number + imageId: number + imageUrl: string +} + +interface LIKE { + likeId: number + nickName: string +} +interface FEEDATA { + boardId: number + images: IMAGE + likeCount: number + likelist: LIKE[] + nickName: string + temperature: number + weather: string + weatherIcon?: string +} export default function Mypage() { + // 회원 정보 + const [userPofile, setUserProfile] = useState(null) + const [userImage, setUserImage] = useState('') // 프로필 이미지 + const [refreshProfile, setRefreshProfile] = useState(false) // 회원 정보 변경했을 때 + const [myPostData, setMyPostData] = useState([]) + const [myLikePostData, setMyLikePostData] = useState([]) + + // 회원 정보 불러오기 + useEffect(() => { + const fetchData = async () => { + try { + // 프로필 데이터 가져오기 + const response = await axios({ + method: 'POST', + url: `https://www.jerneithe.site/user/api/profile`, + headers: { + Authorization: 'Bearer ', + }, + data: { + email: localStorage.getItem('user_email'), + }, + }) + + setUserProfile(response.data) + setUserImage(response.data.image) + + console.log('유저 data: ', response.data) + + // ----------------------------------------- + + // 게시물 데이터 가져오기 + const req = await axios.get('https://www.jerneithe.site/board/list') + const data: FEEDATA[] = req.data + + const filteredData = data.filter( + item => item.nickName === userPofile.nickname, + ) + setMyPostData(filteredData) + + const filteredLikeData = data.filter(item => + item.likelist.some(like => like.nickName === userPofile.nickname), + ) + setMyLikePostData(filteredLikeData) + } catch (error) { + console.error('데이터 로딩 에러: ', error) + } + } + fetchData() + }, [refreshProfile]) + return ( <> - - - + + ) }