Skip to content

Commit

Permalink
[#474] 리프레시 토큰이 만료된 경우 에러 페이지로 넘어가는 이슈 수정 (#483)
Browse files Browse the repository at this point in the history
  • Loading branch information
minjongbaek authored and gxxrxn committed Jun 17, 2024
1 parent f452642 commit 633da9f
Show file tree
Hide file tree
Showing 23 changed files with 128 additions and 110 deletions.
48 changes: 38 additions & 10 deletions src/apis/core/axios.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,8 +5,6 @@ import {
isAuthFailedError,
isAuthRefreshError,
isAxiosErrorWithCustomCode,
setAxiosAuthHeader,
updateToken,
} from '@/utils/helpers';
import isClient from '@/utils/isClient';
import webStorage from '@/utils/storage';
Expand Down Expand Up @@ -53,10 +51,7 @@ const responseHandler = async (error: unknown) => {
}

if (isAuthFailedError(code)) {
storage.remove();
if (isClient()) {
history.pushState('', '', '/');
}
removeToken();
}
} else {
console.error('예상하지 못한 오류가 발생했어요.\n', error);
Expand All @@ -65,12 +60,45 @@ const responseHandler = async (error: unknown) => {
return Promise.reject(error);
};

const silentRefresh = (originRequest: InternalAxiosRequestConfig) => {
return updateToken().then(newToken => {
const silentRefresh = async (originRequest: InternalAxiosRequestConfig) => {
try {
const newToken = await updateToken();
storage.set(newToken);
setAxiosAuthHeader(originRequest, newToken);
return publicApi(originRequest);
});
return await publicApi(originRequest);
} catch {
removeToken();
}
};

const updateToken = async () => {
try {
const {
data: { accessToken },
} = await axios.post<{ accessToken: string }>('/service-api/auth/token');

if (!accessToken) {
throw new Error('새로운 accessToken을 받아오지 못했어요.');
}

return accessToken;
} catch (error) {
return Promise.reject(error);
}
};

const removeToken = () => {
storage.remove();
if (isClient()) {
history.pushState('', '', '/');
}
};

const setAxiosAuthHeader = (
config: InternalAxiosRequestConfig,
token: string
) => {
config.headers['Authorization'] = `Bearers ${token}`;
};

publicApi.interceptors.request.use(requestHandler);
Expand Down
7 changes: 5 additions & 2 deletions src/app/book/search/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import useBookSearchQuery from '@/queries/book/useBookSearchQuery';
import useRecentSearchesQuery from '@/queries/book/useRecentSearchesQuery';

import useDebounceValue from '@/hooks/useDebounce';
import { isAuthed } from '@/utils/helpers/auth';
import { checkAuthentication } from '@/utils/helpers';

import TopHeader from '@/v1/base/TopHeader';
import BookSearchInput from '@/v1/bookSearch/BookSearchInput';
Expand All @@ -21,6 +21,7 @@ import BookSearchResults from '@/v1/bookSearch/SearchResult';
*/

const BookSearch = () => {
const isAuthenticated = checkAuthentication();
const [inputSearchValue, setInputSearchValue] = useState<string>('');

const queryKeyword = useDebounceValue(inputSearchValue, 1000);
Expand All @@ -32,7 +33,9 @@ const BookSearch = () => {
page: 1,
pageSize: 12,
});
const recentSearchesInfo = useRecentSearchesQuery({ enabled: isAuthed() });
const recentSearchesInfo = useRecentSearchesQuery({
enabled: isAuthenticated,
});

const searchedBooks = bookSearchInfo.isSuccess
? bookSearchInfo.data.pages.flatMap(page => page.searchBookResponseList)
Expand Down
7 changes: 4 additions & 3 deletions src/app/bookarchive/page.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
'use client';

import useMyProfileQuery from '@/queries/user/useMyProfileQuery';
import { isAuthed } from '@/utils/helpers';
import { checkAuthentication } from '@/utils/helpers';
import { Suspense } from 'react';
import useMounted from '@/hooks/useMounted';
import BookArchiveForAuth from '@/v1/bookArchive/BookArchiveForAuth';
Expand All @@ -21,13 +21,14 @@ export default function BookArchivePage() {
}

const Contents = () => {
const isAuthenticated = checkAuthentication();
const { data: userData } = useMyProfileQuery({
enabled: isAuthed(),
enabled: isAuthenticated,
});
const mounted = useMounted();
if (!mounted) return null;

return isAuthed() ? (
return isAuthenticated ? (
<BookArchiveForAuth userJobGroup={userData.job.jobGroupName} />
) : (
<BookArchiveForUnAuth />
Expand Down
8 changes: 5 additions & 3 deletions src/app/bookshelf/[bookshelfId]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,7 @@ import useBookShelfBooksQuery from '@/queries/bookshelf/useBookShelfBookListQuer
import useBookShelfInfoQuery from '@/queries/bookshelf/useBookShelfInfoQuery';
import useMutateBookshelfLikeQuery from '@/queries/bookshelf/useMutateBookshelfLikeQuery';
import useToast from '@/v1/base/Toast/useToast';
import { isAuthed } from '@/utils/helpers';
import { checkAuthentication } from '@/utils/helpers';
import { IconKakao } from '@public/icons';
import TopNavigation from '@/v1/base/TopNavigation';
import BookShelfRow from '@/v1/bookShelf/BookShelfRow';
Expand All @@ -26,6 +26,7 @@ export default function UserBookShelfPage({
bookshelfId: APIBookshelf['bookshelfId'];
};
}) {
const isAuthenticated = checkAuthentication();
const { data, isSuccess } = useBookShelfInfoQuery({ bookshelfId });
const { mutate: mutateBookshelfLike } =
useMutateBookshelfLikeQuery(bookshelfId);
Expand All @@ -34,7 +35,7 @@ export default function UserBookShelfPage({
if (!isSuccess) return null;

const handleClickLikeButton = () => {
if (!isAuthed()) {
if (!isAuthenticated) {
showToast({ message: '로그인 후 이용해주세요.', type: 'normal' });
return;
}
Expand Down Expand Up @@ -84,6 +85,7 @@ const BookShelfContent = ({
bookshelfId: APIBookshelf['bookshelfId'];
userNickname: APIBookshelfInfo['userNickname'];
}) => {
const isAuthenticated = checkAuthentication();
const { ref, inView } = useInView();

const {
Expand All @@ -104,7 +106,7 @@ const BookShelfContent = ({
// TODO: Suspense 적용
if (!isSuccess) return null;

return isAuthed() ? (
return isAuthenticated ? (
<>
{booksData.pages.map(page =>
page.books.map((rowBooks, idx) => (
Expand Down
5 changes: 3 additions & 2 deletions src/app/group/[groupId]/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

import Link from 'next/link';

import { isAuthed } from '@/utils/helpers';
import { checkAuthentication } from '@/utils/helpers';
import { KAKAO_LOGIN_URL } from '@/constants/url';

import SSRSafeSuspense from '@/components/SSRSafeSuspense';
Expand All @@ -17,6 +17,7 @@ const DetailBookGroupPage = ({
}: {
params: { groupId: number };
}) => {
const isAuthenticated = checkAuthentication();
return (
<>
<BookGroupNavigation groupId={groupId}>
Expand All @@ -35,7 +36,7 @@ const DetailBookGroupPage = ({
<BookGroupCommentList groupId={groupId} />
</div>
</div>
{isAuthed() ? (
{isAuthenticated ? (
<JoinBookGroupButton groupId={groupId} />
) : (
<LoginBottomActionButton />
Expand Down
10 changes: 6 additions & 4 deletions src/app/group/page.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -16,11 +16,12 @@ import DetailBookGroupCard, {
import useEntireGroupsQuery from '@/queries/group/useEntireGroupsQuery';
import useMyGroupsQuery from '@/queries/group/useMyGroupQuery';
import { useMyProfileId } from '@/queries/user/useMyProfileQuery';
import { isAuthed } from '@/utils/helpers';
import { checkAuthentication } from '@/utils/helpers';
import useMounted from '@/hooks/useMounted';
import Loading from '@/v1/base/Loading';

const GroupPage = () => {
const isAuthenticated = checkAuthentication();
const handleSearchInputClick = () => {
alert('아직 준비 중인 기능이에요.');
};
Expand All @@ -31,7 +32,7 @@ const GroupPage = () => {
<div className="flex w-full flex-col gap-[2rem]">
<SearchGroupInput onClick={handleSearchInputClick} />
<SSRSafeSuspense fallback={<PageSkeleton />}>
{isAuthed() && <MyBookGroupList />}
{isAuthenticated && <MyBookGroupList />}
<EntireBookGroupList />
</SSRSafeSuspense>
</div>
Expand All @@ -45,10 +46,11 @@ const GroupPage = () => {
export default GroupPage;

const MyBookGroupList = () => {
const isAuthenticated = checkAuthentication();
const {
data: { bookGroups },
} = useMyGroupsQuery({ enabled: isAuthed() });
const { data: myId } = useMyProfileId({ enabled: isAuthed() });
} = useMyGroupsQuery({ enabled: isAuthenticated });
const { data: myId } = useMyProfileId({ enabled: isAuthenticated });

return (
<div className="flex gap-[1rem] overflow-scroll">
Expand Down
16 changes: 7 additions & 9 deletions src/app/profile/me/add/page.tsx
Original file line number Diff line number Diff line change
@@ -1,25 +1,23 @@
'use client';

import { Suspense } from 'react';
import useAllJobQuery from '@/queries/job/useAllJobQuery';

import { isAuthed } from '@/utils/helpers';
import AuthRequired from '@/ui/AuthRequired';
import { checkAuthentication } from '@/utils/helpers';

import AddJobProfile from '@/v1/profile/AddJobProfile';
import SSRSafeSuspense from '@/components/SSRSafeSuspense';

const AddJobProfilePage = () => {
return (
<AuthRequired>
<Suspense fallback={null}>
<Contents />
</Suspense>
</AuthRequired>
<SSRSafeSuspense fallback={null}>
<Contents />
</SSRSafeSuspense>
);
};

const Contents = () => {
const allJobQuery = useAllJobQuery({ enabled: isAuthed() });
const isAuthenticated = checkAuthentication();
const allJobQuery = useAllJobQuery({ enabled: isAuthenticated });

return allJobQuery.isSuccess ? (
<AddJobProfile jobCategories={allJobQuery.data.jobGroups} />
Expand Down
16 changes: 7 additions & 9 deletions src/app/profile/me/edit/page.tsx
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
'use client';

import { Suspense } from 'react';
import useAllJobQuery from '@/queries/job/useAllJobQuery';
import useMyProfileQuery from '@/queries/user/useMyProfileQuery';

import { isAuthed } from '@/utils/helpers';
import AuthRequired from '@/ui/AuthRequired';
import { checkAuthentication } from '@/utils/helpers';

import EditProfile from '@/v1/profile/EditProfile';
import SSRSafeSuspense from '@/components/SSRSafeSuspense';

/**
* @todo
Expand All @@ -16,16 +15,15 @@ import EditProfile from '@/v1/profile/EditProfile';

const EditProfilePage = () => {
return (
<AuthRequired>
<Suspense fallback={null}>
<Contents />
</Suspense>
</AuthRequired>
<SSRSafeSuspense fallback={null}>
<Contents />
</SSRSafeSuspense>
);
};

const Contents = () => {
const allJobQuery = useAllJobQuery({ enabled: isAuthed() });
const isAuthenticated = checkAuthentication();
const allJobQuery = useAllJobQuery({ enabled: isAuthenticated });
const { data: profileData } = useMyProfileQuery();

return allJobQuery.isSuccess ? (
Expand Down
5 changes: 3 additions & 2 deletions src/app/profile/me/group/page.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
'use client';

import useMyGroupsQuery from '@/queries/group/useMyGroupQuery';
import { isAuthed } from '@/utils/helpers';
import { checkAuthentication } from '@/utils/helpers';

import BackButton from '@/v1/base/BackButton';
import TopNavigation from '@/v1/base/TopNavigation';
Expand All @@ -22,7 +22,8 @@ const UserGroupPage = () => {
};

const UserGroupContent = () => {
const { data, isSuccess } = useMyGroupsQuery({ enabled: isAuthed() });
const isAuthenticated = checkAuthentication();
const { data, isSuccess } = useMyGroupsQuery({ enabled: isAuthenticated });

if (!isSuccess) {
return (
Expand Down
5 changes: 3 additions & 2 deletions src/app/profile/me/page.tsx
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
'use client';

import { useRouter } from 'next/navigation';
import { isAuthed, removeAuth } from '@/utils/helpers';
import { checkAuthentication, removeAuth } from '@/utils/helpers';
import userAPI from '@/apis/user';
import TopHeader from '@/v1/base/TopHeader';
import ProfileInfo from '@/v1/profile/info/ProfileInfo';
Expand All @@ -19,9 +19,10 @@ const USER_ID = 'me';
const KAKAO_LOGIN_URL = `${process.env.NEXT_PUBLIC_API_URL}/oauth2/authorize/kakao?redirect_uri=${process.env.NEXT_PUBLIC_CLIENT_REDIRECT_URI}`;

const MyProfilePage = () => {
const isAuthenticated = checkAuthentication();
return (
<SSRSafeSuspense fallback={<Loading fullpage />}>
{isAuthed() ? <MyProfileForAuth /> : <MyProfileForUnAuth />}
{isAuthenticated ? <MyProfileForAuth /> : <MyProfileForUnAuth />}
</SSRSafeSuspense>
);
};
Expand Down
10 changes: 7 additions & 3 deletions src/ui/BookDetail/BookCommentList.tsx
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,10 @@ import type { APIBookComment, APIBookmarkedUserList } from '@/types/book';
import { SERVICE_ERROR_MESSAGE } from '@/constants';
import { useToast } from '@/hooks/toast';
import LoginBottomSheet from '@/ui/LoginBottomSheet';
import { isAuthed, isAxiosErrorWithCustomCode } from '@/utils/helpers';
import {
checkAuthentication,
isAxiosErrorWithCustomCode,
} from '@/utils/helpers';

interface Props {
bookId: number;
Expand All @@ -25,6 +28,7 @@ type CommentType = 'me' | 'user';
type CommentRecordType = Record<CommentType, APIBookComment[]>;

const BookCommentList = ({ bookId, isInMyBookshelf }: Props) => {
const isAuthenticated = checkAuthentication();
const { showToast } = useToast();
const commentTextAreaRef = useRef<HTMLTextAreaElement>(null);
const bookCommentsQueryInfo = useBookCommentsQuery(bookId);
Expand Down Expand Up @@ -104,7 +108,7 @@ const BookCommentList = ({ bookId, isInMyBookshelf }: Props) => {
};

const handleCreateCommentDrawerOpen = () => {
if (!isAuthed()) {
if (!isAuthenticated) {
onLoginBottomSheetOpen();
return;
}
Expand All @@ -122,7 +126,7 @@ const BookCommentList = ({ bookId, isInMyBookshelf }: Props) => {

return (
<VStack align="stretch" spacing="2rem" width="100%" pt="1rem">
{!isAuthed() && (
{!isAuthenticated && (
<LoginBottomSheet
isOpen={isLoginBottomSheetOpen}
onClose={onLoginBottomSheetsClose}
Expand Down
Loading

0 comments on commit 633da9f

Please sign in to comment.