diff --git a/src/domains/community/api/fetchComment.ts b/src/domains/community/api/fetchComment.ts index 4d66342c..c4d1ffef 100644 --- a/src/domains/community/api/fetchComment.ts +++ b/src/domains/community/api/fetchComment.ts @@ -48,7 +48,6 @@ export const postComments = async (postId: number | ParamValue, content: string) }; export async function updateComment( - accessToken: string | null, postId: number | ParamValue, commentId: number, content: string @@ -57,8 +56,8 @@ export async function updateComment( method: 'PATCH', headers: { 'Content-Type': 'application/json', - Authorization: `Bearer ${accessToken}`, }, + credentials: 'include', body: JSON.stringify({ content }), }); @@ -69,16 +68,10 @@ export async function updateComment( } } -export async function deleteComment( - accessToken: string | null, - postId: number | ParamValue, - commentId: number -): Promise { +export async function deleteComment(postId: number | ParamValue, commentId: number): Promise { const response = await fetch(`${getApi}/posts/${postId}/comments/${commentId}`, { method: 'DELETE', - headers: { - Authorization: `Bearer ${accessToken}`, - }, + credentials: 'include', }); if (!response.ok) { diff --git a/src/domains/community/detail/Comment.tsx b/src/domains/community/detail/Comment.tsx index f7009de8..ea93f631 100644 --- a/src/domains/community/detail/Comment.tsx +++ b/src/domains/community/detail/Comment.tsx @@ -12,10 +12,9 @@ type Props = { }; function Comment({ postId }: Props) { - const { user, accessToken } = useAuthStore( + const { user } = useAuthStore( useShallow((state) => ({ user: state.user, - accessToken: state.accessToken, })) ); const { @@ -29,7 +28,7 @@ function Comment({ postId }: Props) { handleAskDeleteComment, handleConfirmDelete, loadMoreComments, - } = useComments(postId, user, accessToken); + } = useComments(postId, user); return ( <> diff --git a/src/domains/community/hook/useComment.ts b/src/domains/community/hook/useComment.ts index d94e0f90..e7340020 100644 --- a/src/domains/community/hook/useComment.ts +++ b/src/domains/community/hook/useComment.ts @@ -5,7 +5,7 @@ import { CommentType } from '../types/post'; import { User } from '@/domains/shared/store/auth'; import { ParamValue } from 'next/dist/server/request/params'; -export function useComments(postId: ParamValue, user: User | null, accessToken?: string | null) { +export function useComments(postId: ParamValue, user: User | null) { const [comments, setComments] = useState(null); const [isEnd, setIsEnd] = useState(false); const [isLoading, setIsLoading] = useState(false); @@ -31,7 +31,7 @@ export function useComments(postId: ParamValue, user: User | null, accessToken?: return; } try { - await updateComment(accessToken!, postId, commentId, content); + await updateComment(postId, commentId, content); setComments((prev) => prev ? prev.map((comment) => @@ -59,7 +59,7 @@ export function useComments(postId: ParamValue, user: User | null, accessToken?: if (!deleteTarget) return; try { - await deleteComment(accessToken!, deleteTarget.postId, deleteTarget.commentId); + await deleteComment(deleteTarget.postId, deleteTarget.commentId); setComments((prev) => prev ? prev.filter((c) => c.commentId !== deleteTarget.commentId) : prev ); diff --git a/src/domains/login/components/ClientInitHook.tsx b/src/domains/login/components/ClientInitHook.tsx index a73a7ba9..034d2845 100644 --- a/src/domains/login/components/ClientInitHook.tsx +++ b/src/domains/login/components/ClientInitHook.tsx @@ -2,10 +2,18 @@ import { useFetchInterceptor } from '@/shared/hook/useFetchInterceptor'; import { useIdleLogout } from '../hook/useIdleLogout'; +import { useEffect } from 'react'; +import { useAuthStore } from '@/domains/shared/store/auth'; function ClientInitHook() { + const checkAuth = useAuthStore((state) => state.checkAuth); + useIdleLogout(); useFetchInterceptor(); + + useEffect(() => { + checkAuth(); + }, [checkAuth]); return null; } export default ClientInitHook; diff --git a/src/domains/login/hook/useIdleLogout.ts b/src/domains/login/hook/useIdleLogout.ts index c2cfd493..d8708917 100644 --- a/src/domains/login/hook/useIdleLogout.ts +++ b/src/domains/login/hook/useIdleLogout.ts @@ -5,7 +5,7 @@ import { useLogout } from './useLogout'; import { useToast } from '@/shared/hook/useToast'; import { useAuthStore } from '@/domains/shared/store/auth'; -const IDLE_TIMEOUT = 4 * 60 * 60 * 1000; +const IDLE_TIMEOUT = 1 * 60 * 1000; export const useIdleLogout = () => { const handleLogout = useLogout(); diff --git a/src/domains/recipe/api/fetchRecipeComment.ts b/src/domains/recipe/api/fetchRecipeComment.ts index 627001ee..80f758a4 100644 --- a/src/domains/recipe/api/fetchRecipeComment.ts +++ b/src/domains/recipe/api/fetchRecipeComment.ts @@ -22,7 +22,6 @@ export const getRecipeComment = async (cocktailId: number): Promise { +export async function deleteRecipeComment(cocktailId: number, commentId: number): Promise { const response = await fetch(`${getApi}/cocktails/${cocktailId}/comments/${commentId}`, { method: 'DELETE', - headers: { - Authorization: `Bearer ${accessToken}`, - }, + credentials: 'include', }); if (!response.ok) { diff --git a/src/domains/recipe/api/useRecipeComment.ts b/src/domains/recipe/api/useRecipeComment.ts index d5aa6f6d..3fa8e6d1 100644 --- a/src/domains/recipe/api/useRecipeComment.ts +++ b/src/domains/recipe/api/useRecipeComment.ts @@ -5,11 +5,7 @@ import { CommentType } from '@/domains/community/types/post'; import { deleteRecipeComment, getRecipeComment, updateComment } from './fetchRecipeComment'; import { useToast } from '@/shared/hook/useToast'; -export function useRecipeComments( - cocktailId: number, - user: User | null, - accessToken: string | null -) { +export function useRecipeComments(cocktailId: number, user: User | null) { const [comments, setComments] = useState(null); const [isEnd, setIsEnd] = useState(false); const [isLoading, setIsLoading] = useState(false); @@ -36,7 +32,7 @@ export function useRecipeComments( return; } try { - await updateComment(accessToken!, cocktailId, commentId, content); + await updateComment(cocktailId, commentId, content); setComments((prev) => prev ? prev.map((comment) => @@ -62,7 +58,7 @@ export function useRecipeComments( if (!deleteTarget) return; try { - await deleteRecipeComment(accessToken!, deleteTarget.cocktailId, deleteTarget.commentId); + await deleteRecipeComment(deleteTarget.cocktailId, deleteTarget.commentId); setComments((prev) => prev ? prev.filter((c) => c.commentId !== deleteTarget.commentId) : prev ); diff --git a/src/domains/recipe/components/details/RecipeComment.tsx b/src/domains/recipe/components/details/RecipeComment.tsx index e85e6ec8..581a0608 100644 --- a/src/domains/recipe/components/details/RecipeComment.tsx +++ b/src/domains/recipe/components/details/RecipeComment.tsx @@ -13,10 +13,9 @@ interface Props { } function RecipeComment({ cocktailId }: Props) { - const { user, accessToken } = useAuthStore( + const { user } = useAuthStore( useShallow((state) => ({ user: state.user, - accessToken: state.accessToken, })) ); @@ -60,7 +59,7 @@ function RecipeComment({ cocktailId }: Props) { deleteTarget, handleConfirmDelete, setDeleteTarget, - } = useRecipeComments(cocktailId, user, accessToken); + } = useRecipeComments(cocktailId, user); return (
diff --git a/src/domains/shared/store/auth.ts b/src/domains/shared/store/auth.ts index 3a662b24..eebb8548 100644 --- a/src/domains/shared/store/auth.ts +++ b/src/domains/shared/store/auth.ts @@ -1,6 +1,5 @@ import { getApi } from '@/app/api/config/appConfig'; import { create } from 'zustand'; -import { persist } from 'zustand/middleware'; export interface User { id: string; @@ -13,68 +12,88 @@ export interface User { interface AuthState { user: User | null; - accessToken: string | null; isLoggedIn: boolean; - setUser: (user: User, token: string) => void; + setUser: (user: User) => void; logout: () => Promise; loginWithProvider: (provider: User['provider']) => void; updateUser: () => Promise; + checkAuth: () => Promise; } -export const useAuthStore = create()( - persist( - (set) => ({ - user: null, - accessToken: null, - isLoggedIn: false, +export const useAuthStore = create()((set) => ({ + user: null, + isLoggedIn: false, - loginWithProvider: (provider) => { - window.location.href = `${getApi}/oauth2/authorization/${provider}`; - }, + loginWithProvider: (provider) => { + window.location.href = `${getApi}/oauth2/authorization/${provider}`; + }, - setUser: (user, token) => { - const updatedUser = { ...user, abv_degree: 5.0 }; - set({ user: updatedUser, accessToken: token, isLoggedIn: true }); - }, + setUser: (user) => { + const updatedUser = { ...user, abv_degree: user.abv_degree ?? 5.0 }; + set({ user: updatedUser, isLoggedIn: true }); + }, - logout: async () => { - try { - await fetch(`${getApi}/user/auth/logout`, { - method: 'POST', - credentials: 'include', - }); - set({ user: null, accessToken: null, isLoggedIn: false }); - } catch (err) { - console.error('로그아웃 실패', err); - } - }, + // 로그아웃 + logout: async () => { + try { + await fetch(`${getApi}/user/auth/logout`, { + method: 'POST', + credentials: 'include', + }); + set({ user: null, isLoggedIn: false }); + } catch (err) { + console.error('로그아웃 실패', err); + } finally { + set({ user: null, isLoggedIn: false }); + } + }, - updateUser: async () => { - try { - const res = await fetch(`${getApi}/user/auth/refresh`, { - method: 'POST', - credentials: 'include', - headers: { 'Content-Type': 'application/json' }, - }); + // idle + refresh 시 호출 + updateUser: async () => { + try { + const res = await fetch(`${getApi}/user/auth/refresh`, { + method: 'POST', + credentials: 'include', + headers: { 'Content-Type': 'application/json' }, + }); - if (!res.ok) throw new Error('토큰 갱신 실패'); - const data = await res.json(); - const userInfo = data?.data?.user; - const accessToken = data?.data?.accessToken; + if (!res.ok) throw new Error('토큰 갱신 실패'); - if (userInfo && accessToken) { - set({ user: userInfo, accessToken, isLoggedIn: true }); - return userInfo; - } - return null; - } catch (err) { - console.error('updateUser 실패', err); - set({ accessToken: null, user: null, isLoggedIn: false }); - return null; - } - }, - }), - { name: 'auth-storage' } // localStorage key - ) -); + const data = await res.json(); + const userInfo = data?.data?.user; + + if (userInfo) { + set({ user: userInfo, isLoggedIn: true }); + return userInfo; + } + return null; + } catch (err) { + console.error('updateUser 실패', err); + set({ user: null, isLoggedIn: false }); + return null; + } + }, + + // 시작 시 로그인 상태 확인 + checkAuth: async () => { + try { + const res = await fetch(`${getApi}/user/auth/me`, { + method: 'GET', + credentials: 'include', + }); + if (!res.ok) throw new Error('인증 실패'); + + const data = await res.json(); + const userInfo = data?.data?.user; + if (userInfo) { + set({ user: userInfo, isLoggedIn: true }); + return userInfo; + } + return null; + } catch { + set({ user: null, isLoggedIn: false }); + return null; + } + }, +}));