Skip to content

Commit

Permalink
feat: react-query 설치 헤더 리패치
Browse files Browse the repository at this point in the history
  • Loading branch information
ymj07168 committed Oct 24, 2024
1 parent 4c8e2f8 commit 35f3479
Show file tree
Hide file tree
Showing 8 changed files with 263 additions and 10 deletions.
38 changes: 38 additions & 0 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

1 change: 1 addition & 0 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down
11 changes: 8 additions & 3 deletions src/App.js
Original file line number Diff line number Diff line change
@@ -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 (
<Routers/>
<QueryClientProvider client={queryClient}>
<Routers />
</QueryClientProvider>
);
}

Expand Down
9 changes: 9 additions & 0 deletions src/api/main.js
Original file line number Diff line number Diff line change
Expand Up @@ -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}`,
},
});
};
9 changes: 6 additions & 3 deletions src/components/common/Header.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -9,14 +9,16 @@ 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();
const navigate = useNavigate();
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) => {
Expand Down Expand Up @@ -50,6 +52,7 @@ const Header = () => {
handleMenuClose();
removeCookie("accessToken");
navigate("/");
refetch();
};

return (
Expand All @@ -69,10 +72,10 @@ const Header = () => {
<IconButton aria-label="search">
<FontAwesomeIcon icon={faMagnifyingGlass} />
</IconButton>
{isLoggedIn ? (
{data ? (
<div className="flex flex-row items-center gap-1">
<img
src="https://velog.velcdn.com/images/jhbae0420/post/fde34804-5927-4b81-a621-5b125c945aed/image.png"
src={data?.profileImage}
alt="profile"
className="w-10 h-10 object-cover rounded-full"
/>
Expand Down
22 changes: 22 additions & 0 deletions src/hooks/useGetUserInfo.jsx
Original file line number Diff line number Diff line change
@@ -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 };
};
8 changes: 4 additions & 4 deletions src/pages/MainPage.jsx
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand Down
175 changes: 175 additions & 0 deletions src/pages/MyPage.jsx
Original file line number Diff line number Diff line change
@@ -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 (
<>
<Header />
<PageContainer>
<ProfileSection />
<hr />
<SubTabBar value={selectedTab} handleChange={handleChange} />
{selectedTab === "write" && (
<div className="flex flex-col gap-3 px-3">
{myPosts?.map((item) => (
<MyCard
id={item.tilId}
title={item.title}
content={item.content}
commentCount={item.commentCount}
likeCount={item.likeCount}
createdAt={item.createdAt}
onClick={() => navigate(`/posts/${item.tilId}`)}
/>
))}
</div>
)}
{selectedTab === "like" && (
<div className="flex flex-col gap-3 px-3">
{likedPosts?.map((item) => (
<MyCard
id={item.tilId}
title={item.title}
content={item.content}
commentCount={item.commentCount}
likeCount={item.likeCount}
createdAt={item.createdAt}
onClick={() => navigate(`/posts/${item.tilId}`)}
/>
))}
</div>
)}
{selectedTab === "statistic" && (
<div className="flex flex-col w-full gap-5 px-2">
<div className="flex flex-row items-center w-full gap-3">
<CountCard
title="전체 작성글 개수"
count={statistics.tilsCount}
icon={faPenToSquare}
/>
<CountCard
title="이번달 작성글 개수"
count={statistics.tilsMonthCount}
icon={faCalendar}
/>
<CountCard
title="받은 좋아요 개수"
count={statistics.receivedLikeCount}
icon={faHeart}
/>
</div>
<div className="flex flex-row p-5 border rounded-md min-h-32">
<div className="flex flex-row items-start gap-3">
<div className="p-2 bg-blue-100 rounded-md">
<FontAwesomeIcon
icon={faPenToSquare}
className="w-5 h-5 text-blue-950"
/>
</div>
<div className="flex flex-col gap-3 mb-3">
<div className="text-lg font-semibold">AI 분석</div>
<div className="text-base font-thin">
{statistics?.analysisResult}
</div>
<div className="flex flex-row gap-2">
<Chip
icon={<FontAwesomeIcon icon={faThumbsUp} />}
label={statistics?.mostValue}
sx={{
padding: "8px",
}}
/>
<Chip
icon={<FontAwesomeIcon icon={faThumbsDown} />}
label={statistics?.leastValue}
sx={{
padding: "8px",
}}
/>
</div>
</div>
</div>
</div>
<div className="w-full h-[300px] xl:h-[500px] lg:h-[400px] md:h-[300px] sm:h-[300px]">
<SimpleBarChart />
</div>

{/* 개인 맞춤형 문제 추천 */}
<div className="flex flex-col items-center justify-center p-5 bg-blue-200 border rounded-lg min-h-40">
<img
src={characterImg}
alt="character"
className="w-[100px] h-[100px] mb-3"
/>
<div className="flex flex-col items-center mb-2">
<div className="text-2xl font-semibold">
{data.name}님은 {statistics?.leastValue} 알고리즘 보완이
필요해요!
</div>
<div className="text-lg font-thin">
{statistics?.leastValue} 핵심 문제를 추천해드릴게요! 문제를
통해 코딩마스터가 되어보아요^^
</div>
</div>
<div className="flex flex-col items-center justify-center w-full gap-2 p-5 border rounded-md bg-slate-50">
<div className="text-xl">
오늘 추천 문제는 백준의 {statistics?.aiRecommendDto.title}
입니다.
</div>
<Button
variant="contained"
color="primary"
onClick={() => {
window.open(`${statistics?.aiRecommendDto.site}`, "_blank");
}}
>
문제 풀러가기
</Button>
</div>
</div>
</div>
)}
</PageContainer>
</>
);
};

export default MyPage;

0 comments on commit 35f3479

Please sign in to comment.