diff --git a/package-lock.json b/package-lock.json
index 5669f0c..6561c66 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -15,6 +15,7 @@
"@fortawesome/react-fontawesome": "^0.2.2",
"@mui/icons-material": "^6.1.4",
"@mui/material": "^6.1.4",
+ "@tanstack/react-query": "^5.59.16",
"@testing-library/jest-dom": "^5.17.0",
"@testing-library/react": "^13.4.0",
"@testing-library/user-event": "^13.5.0",
@@ -4074,6 +4075,30 @@
"tslib": "^2.6.2"
}
},
+ "node_modules/@tanstack/query-core": {
+ "version": "5.59.16",
+ "resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.59.16.tgz",
+ "integrity": "sha512-crHn+G3ltqb5JG0oUv6q+PMz1m1YkjpASrXTU+sYWW9pLk0t2GybUHNRqYPZWhxgjPaVGC4yp92gSFEJgYEsPw==",
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/tannerlinsley"
+ }
+ },
+ "node_modules/@tanstack/react-query": {
+ "version": "5.59.16",
+ "resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.59.16.tgz",
+ "integrity": "sha512-MuyWheG47h6ERd4PKQ6V8gDyBu3ThNG22e1fRVwvq6ap3EqsFhyuxCAwhNP/03m/mLg+DAb0upgbPaX6VB+CkQ==",
+ "dependencies": {
+ "@tanstack/query-core": "5.59.16"
+ },
+ "funding": {
+ "type": "github",
+ "url": "https://github.com/sponsors/tannerlinsley"
+ },
+ "peerDependencies": {
+ "react": "^18 || ^19"
+ }
+ },
"node_modules/@testing-library/dom": {
"version": "10.4.0",
"resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-10.4.0.tgz",
@@ -23809,6 +23834,19 @@
"tslib": "^2.6.2"
}
},
+ "@tanstack/query-core": {
+ "version": "5.59.16",
+ "resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.59.16.tgz",
+ "integrity": "sha512-crHn+G3ltqb5JG0oUv6q+PMz1m1YkjpASrXTU+sYWW9pLk0t2GybUHNRqYPZWhxgjPaVGC4yp92gSFEJgYEsPw=="
+ },
+ "@tanstack/react-query": {
+ "version": "5.59.16",
+ "resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.59.16.tgz",
+ "integrity": "sha512-MuyWheG47h6ERd4PKQ6V8gDyBu3ThNG22e1fRVwvq6ap3EqsFhyuxCAwhNP/03m/mLg+DAb0upgbPaX6VB+CkQ==",
+ "requires": {
+ "@tanstack/query-core": "5.59.16"
+ }
+ },
"@testing-library/dom": {
"version": "10.4.0",
"resolved": "https://registry.npmjs.org/@testing-library/dom/-/dom-10.4.0.tgz",
diff --git a/package.json b/package.json
index 34f481d..0835a85 100644
--- a/package.json
+++ b/package.json
@@ -10,6 +10,7 @@
"@fortawesome/react-fontawesome": "^0.2.2",
"@mui/icons-material": "^6.1.4",
"@mui/material": "^6.1.4",
+ "@tanstack/react-query": "^5.59.16",
"@testing-library/jest-dom": "^5.17.0",
"@testing-library/react": "^13.4.0",
"@testing-library/user-event": "^13.5.0",
diff --git a/src/App.js b/src/App.js
index ca5a0aa..28848f8 100644
--- a/src/App.js
+++ b/src/App.js
@@ -1,9 +1,14 @@
-import './App.css';
-import Routers from './Routers';
+import "./App.css";
+import Routers from "./Routers";
+import { QueryClient, QueryClientProvider } from "@tanstack/react-query";
+
+const queryClient = new QueryClient();
function App() {
return (
-
+
+
+
);
}
diff --git a/src/api/main.js b/src/api/main.js
index 90a332c..f11b91b 100644
--- a/src/api/main.js
+++ b/src/api/main.js
@@ -28,3 +28,12 @@ export const getTILDetail = async ({ tilId }) => {
export const getChallengeDetail = async ({ challengeId }) => {
return await client.get(`/api/challenges/${challengeId}`);
};
+
+// 유저 정보 조회
+export const getUserInfo = async (userToken) => {
+ return await client.get(`/api/member`, {
+ headers: {
+ Authorization: `Bearer ${userToken}`,
+ },
+ });
+};
diff --git a/src/components/common/Header.jsx b/src/components/common/Header.jsx
index 4413e11..aeb6125 100644
--- a/src/components/common/Header.jsx
+++ b/src/components/common/Header.jsx
@@ -9,7 +9,8 @@ import {
} from "@fortawesome/free-solid-svg-icons";
import { useAuth } from "../../hooks/useAuth";
import { useNavigate } from "react-router-dom";
-import { removeCookie } from "../../api/cookie";
+import { getCookie, removeCookie } from "../../api/cookie";
+import { useGetUserInfo } from "../../hooks/useGetUserInfo";
const Header = () => {
const { isLoggedIn } = useAuth();
@@ -17,6 +18,7 @@ const Header = () => {
const [modal, setModal] = React.useState(false);
const [anchorEl, setAnchorEl] = React.useState(null);
const menuOpen = Boolean(anchorEl);
+ const { data, refetch } = useGetUserInfo(getCookie("accessToken"));
// 프로필 메뉴 클릭
const handleMenuClick = (event) => {
@@ -50,6 +52,7 @@ const Header = () => {
handleMenuClose();
removeCookie("accessToken");
navigate("/");
+ refetch();
};
return (
@@ -69,10 +72,10 @@ const Header = () => {
- {isLoggedIn ? (
+ {data ? (

diff --git a/src/hooks/useGetUserInfo.jsx b/src/hooks/useGetUserInfo.jsx
new file mode 100644
index 0000000..96e1db8
--- /dev/null
+++ b/src/hooks/useGetUserInfo.jsx
@@ -0,0 +1,22 @@
+import { useQuery } from "@tanstack/react-query";
+import { getUserInfo } from "../api/main";
+
+export const useGetUserInfo = (token) => {
+ const queryKey = ["userInfo", token];
+
+ const queryFn = async () => {
+ if (token) {
+ const response = await getUserInfo(token);
+ return response.data;
+ }
+ throw new Error("Missing parameters");
+ };
+
+ const { isLoading, isError, data, error, isSuccess, refetch } = useQuery({
+ queryKey,
+ queryFn,
+ enabled: !!token,
+ });
+
+ return { isLoading, isError, data, error, isSuccess, refetch };
+};
diff --git a/src/pages/MainPage.jsx b/src/pages/MainPage.jsx
index fe94c4b..b810a86 100644
--- a/src/pages/MainPage.jsx
+++ b/src/pages/MainPage.jsx
@@ -19,10 +19,10 @@ const MainPage = () => {
};
useEffect(() => {
- setCookie(
- "accessToken",
- "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzb2NpYWwiOiJrYWthbyIsImVtYWlsIjoieW1qMDcxNjhAbmF2ZXIuY29tIiwicHJvZmlsZUltYWdlIjoiaHR0cDovL2sua2FrYW9jZG4ubmV0L2RuL2RmQVd6Zy9idHNKbjdtWWZmby9jN2FncWtvY1lONDVmN3hIQjIxc3ZLL2ltZ182NDB4NjQwLmpwZyIsInJvbGUiOiJNRU1CRVIiLCJuYW1lIjoi7J207Zqo7JuQIiwiaWF0IjoxNzI5NzUxMDg1LCJleHAiOjE3Mjk3ODcwODV9.hvJm84rtzssOWMjVbF3SCjH4rkFRqCIVikIxQc_36_s"
- );
+ // setCookie(
+ // "accessToken",
+ // "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzb2NpYWwiOiJrYWthbyIsImVtYWlsIjoieW1qMDcxNjhAbmF2ZXIuY29tIiwicHJvZmlsZUltYWdlIjoiaHR0cDovL2sua2FrYW9jZG4ubmV0L2RuL2RmQVd6Zy9idHNKbjdtWWZmby9jN2FncWtvY1lONDVmN3hIQjIxc3ZLL2ltZ182NDB4NjQwLmpwZyIsInJvbGUiOiJNRU1CRVIiLCJuYW1lIjoi7J207Zqo7JuQIiwiaWF0IjoxNzI5NzUxMDg1LCJleHAiOjE3Mjk3ODcwODV9.hvJm84rtzssOWMjVbF3SCjH4rkFRqCIVikIxQc_36_s"
+ // );
getTIL({ pageNumber: 0 }).then((res) => setPosts(res.data.content));
getChallenges({ pageSize: 0 }).then((res) =>
setChallenges(res.data.content)
diff --git a/src/pages/MyPage.jsx b/src/pages/MyPage.jsx
index e69de29..b730398 100644
--- a/src/pages/MyPage.jsx
+++ b/src/pages/MyPage.jsx
@@ -0,0 +1,175 @@
+import React, { useEffect, useState } from "react";
+import PageContainer from "../components/common/PageContainer";
+import ProfileSection from "../components/mypage/ProfileSection";
+import SubTabBar from "../components/mypage/SubTabBar";
+import MyCard from "../components/mypage/MyCard";
+import SimpleBarChart from "../components/mypage/SimpleBarChart";
+import { FontAwesomeIcon } from "@fortawesome/react-fontawesome";
+import {
+ faCalendar,
+ faHeart,
+ faPenToSquare,
+ faThumbsDown,
+ faThumbsUp,
+} from "@fortawesome/free-solid-svg-icons";
+import CountCard from "../components/mypage/CountCard";
+import { Button, Chip } from "@mui/material";
+import characterImg from "../images/main-character.png";
+import Header from "../components/common/Header";
+import { getLikeTILs, getMyTILs, getStatistics } from "../api/mypage";
+import { useNavigate } from "react-router-dom";
+import { useGetUserInfo } from "../hooks/useGetUserInfo";
+import { getCookie } from "../api/cookie";
+
+const MyPage = () => {
+ const navigate = useNavigate();
+ const token = getCookie("accessToken");
+ const { data } = useGetUserInfo(token);
+ const [selectedTab, setSelectedTab] = useState("write");
+ const [myPosts, setMyPosts] = useState([]);
+ const [likedPosts, setLikedPosts] = useState([]);
+ const [statistics, setStatistics] = useState(null);
+
+ const handleChange = (event, newValue) => {
+ setSelectedTab(newValue);
+ };
+
+ useEffect(() => {
+ getMyTILs({ pageSize: 0 }).then((res) => setMyPosts(res.data.content));
+ getLikeTILs({ pageSize: 0 }).then((res) => setLikedPosts(res.data.content));
+ getStatistics().then((res) => setStatistics(res.data));
+ }, []);
+
+ return (
+ <>
+
+
+
+
+
+ {selectedTab === "write" && (
+
+ {myPosts?.map((item) => (
+ navigate(`/posts/${item.tilId}`)}
+ />
+ ))}
+
+ )}
+ {selectedTab === "like" && (
+
+ {likedPosts?.map((item) => (
+ navigate(`/posts/${item.tilId}`)}
+ />
+ ))}
+
+ )}
+ {selectedTab === "statistic" && (
+
+
+
+
+
+
+
+
+
+
+
+
+
AI 분석
+
+ {statistics?.analysisResult}
+
+
+ }
+ label={statistics?.mostValue}
+ sx={{
+ padding: "8px",
+ }}
+ />
+ }
+ label={statistics?.leastValue}
+ sx={{
+ padding: "8px",
+ }}
+ />
+
+
+
+
+
+
+
+
+ {/* 개인 맞춤형 문제 추천 */}
+
+

+
+
+ {data.name}님은 {statistics?.leastValue} 알고리즘 보완이
+ 필요해요!
+
+
+ {statistics?.leastValue} 핵심 문제를 추천해드릴게요! 문제를
+ 통해 코딩마스터가 되어보아요^^
+
+
+
+
+ 오늘 추천 문제는 백준의 {statistics?.aiRecommendDto.title}
+ 입니다.
+
+
+
+
+
+ )}
+
+ >
+ );
+};
+
+export default MyPage;