diff --git a/Github-Study b/Github-Study deleted file mode 160000 index d42b139..0000000 --- a/Github-Study +++ /dev/null @@ -1 +0,0 @@ -Subproject commit d42b1392bd67c712c744077a87109b3bfb544a42 diff --git a/src/api/axios.config.ts b/src/api/axios.config.ts index df41e09..a0cb3bc 100644 --- a/src/api/axios.config.ts +++ b/src/api/axios.config.ts @@ -1,3 +1,5 @@ +/* eslint-disable no-param-reassign */ +/* eslint-disable consistent-return */ /* eslint-disable no-underscore-dangle */ import axios from 'axios'; import { getCookie, setCookie } from '@/app/cookies.tsx'; @@ -10,12 +12,12 @@ const reIssuedToken = async () => { const response = await axios.post( `${BASE_URL}/reissue`, { - access_token: getCookie('accessToken'), // 액세스 토큰을 사용하고 있으나, 일반적으로는 사용하지 않습니다. - refresh_token: getCookie('refreshToken'), // 리프레시 토큰 + access_token: getCookie('accessToken'), + refresh_token: getCookie('refreshToken'), }, { headers: { - 'Content-Type': 'application/json', // 요청의 본문 타입을 지정 + 'Content-Type': 'application/json', Authorization: `Bearer ${accessToken}`, }, withCredentials: true, // CORS 요청 시 쿠키를 포함 @@ -29,38 +31,48 @@ const reIssuedToken = async () => { } return response.data; } catch (error) { - throw new Error('토큰 재발급 로직 에러 : ', error || ''); + setCookie('accessToken', ''); + setCookie('refreshToken', ''); } }; const api = axios.create({ withCredentials: true, baseURL: BASE_URL, // 기본 URL 설정 - headers: { - 'Content-Type': 'application/json', - Authorization: `Bearer ${accessToken}`, - }, }); +// 요청 인터셉터를 추가하여 모든 요청에 최신 토큰을 포함시킵니다. +api.interceptors.request.use( + (config) => { + const token = getCookie('accessToken'); // 요청 직전에 액세스 토큰을 쿠키에서 가져옵니다. + config.headers.Authorization = `Bearer ${token}`; + config.headers['Content-Type'] = 'application/json'; + return config; + }, + (error) => Promise.reject(error), +); + api.interceptors.response.use( (response) => response, // 성공 응답은 그대로 반환 async (error) => { - const originalRequest = error.config; - if (error.response.status === 401 && !originalRequest._retry) { - originalRequest._retry = true; // 재요청 플래그를 설정하여 무한 루프 방지 - try { - const data = await reIssuedToken(); // 토큰 재발급 함수 호출 - // 재발급 받은 토큰으로 요청 헤더 설정 - api.defaults.headers.common.Authorization = `Bearer ${data.data.access_token}`; - originalRequest.headers.Authorization = `Bearer ${data.data.access_token}`; + if (accessToken !== undefined) { + const originalRequest = error.config; + if (error.response.status === 401 && !originalRequest._retry) { + originalRequest._retry = true; // 재요청 플래그를 설정하여 무한 루프 방지 + try { + const data = await reIssuedToken(); // 토큰 재발급 함수 호출 + // 재발급 받은 토큰으로 요청 헤더 설정 + api.defaults.headers.common.Authorization = `Bearer ${data.data.access_token}`; + originalRequest.headers.Authorization = `Bearer ${data.data.access_token}`; - return api(originalRequest); // 원래 요청 재시도 - } catch (refreshError) { - return Promise.reject(refreshError); + return api(originalRequest); // 원래 요청 재시도 + } catch (refreshError) { + return Promise.reject(refreshError); + } } - } - return Promise.reject(error); + return Promise.reject(error); + } }, ); @@ -69,8 +81,35 @@ export { api }; export const formApi = axios.create({ withCredentials: true, baseURL: BASE_URL, - headers: { - 'Content-Type': 'multipart/form-data', - Authorization: `Bearer ${accessToken}`, - }, }); + +formApi.interceptors.request.use( + (config) => { + const token = getCookie('accessToken'); + config.headers.Authorization = `Bearer ${token}`; + return config; + }, + (error) => Promise.reject(error), +); + +formApi.interceptors.response.use( + (response) => response, + async (error) => { + if (accessToken !== undefined) { + const originalRequest = error.config; + if (error.response.status === 401 && !originalRequest._retry) { + originalRequest._retry = true; + try { + const data = await reIssuedToken(); + formApi.defaults.headers.common.Authorization = `Bearer ${data.data.access_token}`; + originalRequest.headers.Authorization = `Bearer ${data.data.access_token}`; + + return formApi(originalRequest); + } catch (refreshError) { + return Promise.reject(refreshError); + } + } + return Promise.reject(error); + } + }, +); diff --git a/src/api/nearMeeting.ts b/src/api/nearMeeting.ts index c8f4524..cad71e3 100644 --- a/src/api/nearMeeting.ts +++ b/src/api/nearMeeting.ts @@ -13,7 +13,7 @@ const searchMeetings = async ( ); return response.data; } catch (error) { - throw new Error('meeting search api request error : ', error || ''); + throw new Error('주변 모임 검색 에러 : ', error || ''); } }; diff --git a/src/app/account/[userIdParam]/Classification.tsx b/src/app/account/[userIdParam]/Classification.tsx index 51f981d..33473a8 100644 --- a/src/app/account/[userIdParam]/Classification.tsx +++ b/src/app/account/[userIdParam]/Classification.tsx @@ -21,7 +21,7 @@ const Classification = ({ id }: accountIdProps) => { const loadMoreRef = useRef(null); const { data, fetchNextPage, hasNextPage, refetch } = useInfiniteQuery({ - queryKey: ['myMeetingList'], + queryKey: ['My Meeting List', activeTab], queryFn: ({ pageParam = 0 }: { pageParam: number }) => getMyMeetingList(activeTab, id, pageParam, 24), initialPageParam: 0, diff --git a/src/app/components/Header.tsx b/src/app/components/Header.tsx index 38554f7..05f29ee 100644 --- a/src/app/components/Header.tsx +++ b/src/app/components/Header.tsx @@ -1,6 +1,9 @@ +/* eslint-disable react-hooks/exhaustive-deps */ +/* eslint-disable operator-linebreak */ + 'use client'; -import { useState } from 'react'; +import { useEffect, useState } from 'react'; import { Montserrat } from 'next/font/google'; import Link from 'next/link'; import { usePathname, useRouter } from 'next/navigation'; @@ -8,7 +11,7 @@ import category from '@/util/category.json'; import { useQuery } from '@tanstack/react-query'; import { login, logout } from '@/api/user.ts'; import ignorePath from '../styles/ignorePath.ts'; -import { removeCookie } from '../cookies.tsx'; +import { getCookie, removeCookie } from '../cookies.tsx'; const mont = Montserrat({ subsets: ['latin'], weight: ['500'] }); @@ -25,6 +28,21 @@ function Header() { queryFn: login, }); + const checkAuthentication = async () => { + if ( + !getCookie('accessToken') && + !getCookie('refreshToken') && + path !== '/auth/login' && + path !== '/auth/signup' + ) { + await router.push('/login'); + } + }; + + useEffect(() => { + checkAuthentication(); + }, []); + if (ignorePath().includes(path)) { return null; } diff --git a/src/app/home/Body.tsx b/src/app/home/Body.tsx index 319bfe5..fbcdb95 100644 --- a/src/app/home/Body.tsx +++ b/src/app/home/Body.tsx @@ -50,29 +50,28 @@ function Distance() { const renderSize = 8; - const { data, fetchNextPage, hasNextPage, isFetchingNextPage } = - useInfiniteQuery({ - queryKey: ['Latest Meeting List', latitude, longitude], - queryFn: async ({ pageParam = 0 }) => { - if (latitude !== null && longitude !== null) { - return searchMeetings( - latitude, - longitude, - pageParam, - renderSize, - 'asc', - ); - } - }, - getNextPageParam: (lastPage, allPages) => { - if (lastPage === null) { - return undefined; - } - return allPages.length; - }, - enabled: locationFetched, // 위치 정보를 성공적으로 가져왔을 때만 쿼리 실행 - initialPageParam: 0, - }); + const { data, fetchNextPage, hasNextPage } = useInfiniteQuery({ + queryKey: ['Latest Meeting List', latitude, longitude], + queryFn: async ({ pageParam = 0 }) => { + if (latitude !== null && longitude !== null) { + return searchMeetings( + latitude, + longitude, + pageParam, + renderSize, + 'asc', + ); + } + }, + getNextPageParam: (lastPage, allPages) => { + if (lastPage === null) { + return undefined; + } + return allPages.length; + }, + enabled: locationFetched, // 위치 정보를 성공적으로 가져왔을 때만 쿼리 실행 + initialPageParam: 0, + }); const loadMoreRef = useRef(null); @@ -260,7 +259,7 @@ function Distance() { ), ), )} - {isFetchingNextPage &&
Loading...
} + {/* {isFetchingNextPage &&
Loading...
} */}
diff --git a/src/app/layout.tsx b/src/app/layout.tsx index 12db98f..afaabcc 100644 --- a/src/app/layout.tsx +++ b/src/app/layout.tsx @@ -3,7 +3,7 @@ import type { Metadata } from 'next'; import { Inter } from 'next/font/google'; import './styles/globals.css'; import Script from 'next/script'; -import StoreProvider from './StoreProvider.tsx'; +// import StoreProvider from './StoreProvider.tsx'; import Header from './components/Header.tsx'; import Footer from './components/Footer.tsx'; import QueryProviders from '../lib/QueryProvider.tsx'; @@ -31,14 +31,14 @@ export default function RootLayout({ 로딩중인데요?ㅋㅋ}>
- - -
{children}
-
+ {/* */} + +
{children}
+ {/*
*/}