diff --git a/package-lock.json b/package-lock.json index ee3e4ac82..9c2a2eb9c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -8,6 +8,7 @@ "name": "fe-weekly-mission", "version": "0.1.0", "dependencies": { + "@tanstack/react-query": "^5.56.2", "axios": "^1.7.3", "next": "14.2.5", "react": "^18", @@ -878,6 +879,30 @@ "tslib": "^2.4.0" } }, + "node_modules/@tanstack/query-core": { + "version": "5.56.2", + "resolved": "https://registry.npmjs.org/@tanstack/query-core/-/query-core-5.56.2.tgz", + "integrity": "sha512-gor0RI3/R5rVV3gXfddh1MM+hgl0Z4G7tj6Xxpq6p2I03NGPaJ8dITY9Gz05zYYb/EJq9vPas/T4wn9EaDPd4Q==", + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + } + }, + "node_modules/@tanstack/react-query": { + "version": "5.56.2", + "resolved": "https://registry.npmjs.org/@tanstack/react-query/-/react-query-5.56.2.tgz", + "integrity": "sha512-SR0GzHVo6yzhN72pnRhkEFRAHMsUo5ZPzAxfTMvUxFIDVS6W9LYUp6nXW3fcHVdg0ZJl8opSH85jqahvm6DSVg==", + "dependencies": { + "@tanstack/query-core": "5.56.2" + }, + "funding": { + "type": "github", + "url": "https://github.com/sponsors/tannerlinsley" + }, + "peerDependencies": { + "react": "^18 || ^19" + } + }, "node_modules/@types/hoist-non-react-statics": { "version": "3.3.5", "resolved": "https://registry.npmjs.org/@types/hoist-non-react-statics/-/hoist-non-react-statics-3.3.5.tgz", diff --git a/package.json b/package.json index 74e91472e..09a1dde7a 100644 --- a/package.json +++ b/package.json @@ -9,6 +9,7 @@ "lint": "next lint" }, "dependencies": { + "@tanstack/react-query": "^5.56.2", "axios": "^1.7.3", "next": "14.2.5", "react": "^18", diff --git a/src/api/api.ts b/src/api/api.ts index 16ebc8f18..ff8f84d0a 100644 --- a/src/api/api.ts +++ b/src/api/api.ts @@ -46,23 +46,8 @@ export const getArticlesComment = async ({ } }; -export const postLogin = async () => { - try { - const response = await axiosInstance.post(`/auth/signIn`, { - email: "dang96@email.com", - password: "92089208", - }); - - const token = response.data.accessToken; - localStorage.setItem("token", token); - return token; - } catch (err) { - console.error("로그인 토큰 가져오기 오류"); - } -}; - export const postArticlesImage = async (file: File) => { - const token = localStorage.getItem("token"); + const token = localStorage.getItem("userInfo"); if (!token) { console.error("Error Messages: 토큰이 없습니다."); @@ -84,7 +69,8 @@ export const postArticlesImage = async (file: File) => { }; export const postArticles = async ({ image, content, title }: ArticlesAdd) => { - const token = localStorage.getItem("token"); + const token = localStorage.getItem("userInfo"); + if (!token) { console.error("Error Messages: 토큰이 없습니다."); diff --git a/src/api/authApi.ts b/src/api/authApi.ts new file mode 100644 index 000000000..5e71638ff --- /dev/null +++ b/src/api/authApi.ts @@ -0,0 +1,39 @@ +import { axiosInstance } from "./axiosInstance"; + +export type LoginType = { + email: string, + password: string, +} + +export type SignUpType = LoginType & { + nickname: string, + passwordConfirmation: string, +} + +export const postLogin = async ({email, password}: LoginType) => { + try { + const response = await axiosInstance.post('/auth/signIn', { + email, + password + }) + + return response.data; + } catch (err) { + console.error("로그인 오류" + err) + } +} + +export const postSignUp = async ({email, nickname, password, passwordConfirmation }: SignUpType) => { + try { + const response = await axiosInstance.post('/auth/signUp', { + email, + nickname, + password, + passwordConfirmation + }) + + return response; + } catch (err) { + console.error("회원가입 오류" + err) + } +} \ No newline at end of file diff --git a/src/api/axiosInstance.ts b/src/api/axiosInstance.ts index 55180f5d8..b99b76124 100644 --- a/src/api/axiosInstance.ts +++ b/src/api/axiosInstance.ts @@ -6,11 +6,17 @@ export const axiosInstance = axios.create({ axiosInstance.interceptors.request.use( (config) => { - const token = localStorage.getItem("token"); + const token = localStorage.getItem("userInfo"); - if (token && !config.url?.includes("/auth/signIn")) { - config.headers.Authorization = `Bearer ${token}`; - } + if(token) { + const userInfo = JSON.parse(token); + const userInfoAccessToken = userInfo.accessToken; + + if (userInfoAccessToken && !config.url?.includes("/auth/signIn")) { + config.headers.Authorization = `Bearer ${userInfoAccessToken}`; + } + + } return config; }, diff --git a/src/components/boards/AllBoard.tsx b/src/components/boards/AllBoard.tsx index 1d52459d7..6fed5caf6 100644 --- a/src/components/boards/AllBoard.tsx +++ b/src/components/boards/AllBoard.tsx @@ -8,10 +8,11 @@ import Link from "next/link"; export type AllBoardProps = { articles: ArticlesList[]; - setArticleQuery: React.Dispatch>; + setSortOrder: React.Dispatch>; + setSearchKeyword: React.Dispatch>; }; -export default function AllBoard({ articles, setArticleQuery }: AllBoardProps) { +export default function AllBoard({ articles, setSortOrder, setSearchKeyword }: AllBoardProps) { return ( @@ -19,8 +20,8 @@ export default function AllBoard({ articles, setArticleQuery }: AllBoardProps) { 글쓰기 - - + + {articles.map((article) => { diff --git a/src/components/boards/BoardOrder.tsx b/src/components/boards/BoardOrder.tsx index 84b5bfc46..531322aa0 100644 --- a/src/components/boards/BoardOrder.tsx +++ b/src/components/boards/BoardOrder.tsx @@ -2,9 +2,9 @@ import styled from "styled-components"; import { useState } from "react"; import { AllBoardProps } from "../../components/boards/AllBoard"; -type SearchOrderProp = Pick; +type SearchOrderProp = Pick; -export default function BoardOrder({ setArticleQuery }: SearchOrderProp) { +export default function BoardOrder({ setSortOrder }: SearchOrderProp) { const ORDER_NEW = "최신순"; const ORDER_LIKE = "좋아요순"; const [dropText, setDropText] = useState(ORDER_NEW); @@ -13,10 +13,7 @@ export default function BoardOrder({ setArticleQuery }: SearchOrderProp) { const handleClick = (order: string) => { setDropText(order); setDropDisplay(false); - setArticleQuery((prev) => ({ - ...prev, - orderBy: order === ORDER_NEW ? "recent" : "like", - })); + setSortOrder(order === ORDER_NEW ? "recent" : "like"); }; return ( diff --git a/src/components/boards/BoardSearch.tsx b/src/components/boards/BoardSearch.tsx index 5d451d6d3..e182b6d81 100644 --- a/src/components/boards/BoardSearch.tsx +++ b/src/components/boards/BoardSearch.tsx @@ -3,11 +3,17 @@ import SearchImage from "../../../public/images/i-search.png"; import { AllBoardProps } from "../../components/boards/AllBoard"; import { useState } from "react"; -type SearchOrderProp = Pick; +type SearchOrderProp = Pick; -export default function BoardSearch({ setArticleQuery }: SearchOrderProp) { +export default function BoardSearch({ setSearchKeyword }: SearchOrderProp) { const [searchInput, setSearchInput] = useState(""); + const handleKeyDown = (e: React.KeyboardEvent) => { + if (e.key === "Enter") { + setSearchKeyword(searchInput); + } + }; + return ( { setSearchInput(e.target.value); }} - onKeyDown={(e) => { - e.key === "Enter" - ? setArticleQuery((prev) => ({ ...prev, keyword: searchInput })) - : ""; - }} + onKeyDown={handleKeyDown} placeholder="검색할 상품을 입력해주세요" /> diff --git a/src/components/layout/Header.tsx b/src/components/layout/Header.tsx index 63a9db6e2..43ce5ef0a 100644 --- a/src/components/layout/Header.tsx +++ b/src/components/layout/Header.tsx @@ -5,11 +5,26 @@ import { LinkButton } from "@/styles/ButtonStyle"; import { useRouter } from "next/router"; import Logo from "../../../public/images/logo.png"; import ProfileImage from "../../../public/images/i-profile.png"; +import { useEffect, useState } from 'react'; export default function Header() { const router = useRouter(); const { pathname } = router; const startPathName = pathname.startsWith("/boards"); + const [isLoggedIn, setIsLoggedIn] = useState(false); + const [isLogout, setIsLogout] = useState(false); + + useEffect(() => { + const userInfo = localStorage.getItem('userInfo'); + setIsLoggedIn(!!userInfo); + setIsLogout(true); + }, [isLogout]) + + const handleLogout = () => { + localStorage.removeItem('userInfo'); + setIsLogout(false); + router.push('/login'); + } const MENU_COLOR = { on: "#3692ff", @@ -28,7 +43,7 @@ export default function Header() { alt="판다마켓" /> - + {isLoggedIn &&
  • 중고마켓
-
+
} - {pathname === "/boards" ? ( + {isLoggedIn ? ( 프로필 이미지 + + ) : ( - 로그인 + 로그인 )} diff --git a/src/pages/_app.tsx b/src/pages/_app.tsx index e4ebb3bf7..f73f3f1bc 100644 --- a/src/pages/_app.tsx +++ b/src/pages/_app.tsx @@ -6,6 +6,9 @@ import "@/styles/global.css"; import type { AppProps } from "next/app"; import Head from "next/head"; +import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; + +const queryClient = new QueryClient(); export default function App({ Component, pageProps }: AppProps) { return ( @@ -25,7 +28,9 @@ export default function App({ Component, pageProps }: AppProps) {
- + + +