From 9e1cc29ec95aba06436c29a35db2962ab0ecabb4 Mon Sep 17 00:00:00 2001 From: manNomi Date: Sat, 14 Feb 2026 19:15:26 +0900 Subject: [PATCH 1/3] =?UTF-8?q?=F0=9F=94=A7=20auth=20=EC=A0=84=EC=97=AD=20?= =?UTF-8?q?=EC=8A=A4=ED=86=A0=EC=96=B4=EC=97=90=20userRole=20=EC=83=81?= =?UTF-8?q?=ED=83=9C=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/web/src/lib/zustand/useAuthStore.ts | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/apps/web/src/lib/zustand/useAuthStore.ts b/apps/web/src/lib/zustand/useAuthStore.ts index e7de5c47..a3a8c865 100644 --- a/apps/web/src/lib/zustand/useAuthStore.ts +++ b/apps/web/src/lib/zustand/useAuthStore.ts @@ -1,10 +1,28 @@ import { create } from "zustand"; import { persist } from "zustand/middleware"; +import { UserRole } from "@/types/mentor"; + +const parseUserRoleFromToken = (token: string | null): UserRole | null => { + if (!token) return null; + + try { + const payload = JSON.parse(atob(token.split(".")[1])) as { role?: string }; + + if (payload.role === UserRole.MENTOR || payload.role === UserRole.MENTEE || payload.role === UserRole.ADMIN) { + return payload.role; + } + + return null; + } catch { + return null; + } +}; type RefreshStatus = "idle" | "refreshing" | "success" | "failed"; interface AuthState { accessToken: string | null; + userRole: UserRole | null; isAuthenticated: boolean; isLoading: boolean; isInitialized: boolean; @@ -20,6 +38,7 @@ const useAuthStore = create()( persist( (set) => ({ accessToken: null, + userRole: null, isAuthenticated: false, isLoading: false, isInitialized: false, @@ -28,6 +47,7 @@ const useAuthStore = create()( setAccessToken: (token) => { set({ accessToken: token, + userRole: parseUserRoleFromToken(token), isAuthenticated: true, isLoading: false, isInitialized: true, @@ -38,6 +58,7 @@ const useAuthStore = create()( clearAccessToken: () => { set({ accessToken: null, + userRole: null, isAuthenticated: false, isLoading: false, isInitialized: true, @@ -66,6 +87,7 @@ const useAuthStore = create()( onRehydrateStorage: () => (state) => { // hydration 완료 후 isInitialized를 true로 설정 if (state) { + state.userRole = parseUserRoleFromToken(state.accessToken); state.isInitialized = true; } }, From 88b244a6b478ebc235eed9ec0ea891eecd7866fa Mon Sep 17 00:00:00 2001 From: manNomi Date: Sat, 14 Feb 2026 19:15:34 +0900 Subject: [PATCH 2/3] =?UTF-8?q?=F0=9F=90=9B=20=EB=A9=98=ED=86=A0=20?= =?UTF-8?q?=EC=B2=B4=ED=81=AC=20=ED=98=B8=EC=B6=9C=20=EC=A1=B0=EA=B1=B4=20?= =?UTF-8?q?=EB=B0=8F=20=EB=A9=98=ED=86=A0=20=ED=8E=98=EC=9D=B4=EC=A7=80=20?= =?UTF-8?q?=EC=9D=B4=EB=8F=99=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../mentor/MentorApplyCountContent/index.tsx | 28 +++++++++++-------- .../hooks/useExpandCardClickHandler.ts | 6 ++-- 2 files changed, 18 insertions(+), 16 deletions(-) diff --git a/apps/web/src/components/mentor/MentorApplyCountContent/index.tsx b/apps/web/src/components/mentor/MentorApplyCountContent/index.tsx index 00e16474..0a962f85 100644 --- a/apps/web/src/components/mentor/MentorApplyCountContent/index.tsx +++ b/apps/web/src/components/mentor/MentorApplyCountContent/index.tsx @@ -1,21 +1,18 @@ "use client"; -import Link from "next/link"; +import { useRouter } from "next/navigation"; import { useState } from "react"; -import { useGetUnconfirmedMentoringCount } from "@/apis/mentor"; +import { useGetMentoringUncheckedCount } from "@/apis/mentor"; import useAuthStore from "@/lib/zustand/useAuthStore"; import { UserRole } from "@/types/mentor"; -import { tokenParse } from "@/utils/jwtUtils"; const MentorApplyCountContent = () => { - // 로그인 된경우에만 신규 신청 카운트 모달 표시 - const { accessToken, isInitialized } = useAuthStore(); - const isMentor = - tokenParse(accessToken)?.role === UserRole.MENTOR || - tokenParse(accessToken)?.role === UserRole.ADMIN; + const router = useRouter(); + const { isInitialized, isAuthenticated, userRole } = useAuthStore(); + const isMentor = userRole === UserRole.MENTOR; - const { data: count, isSuccess } = useGetUnconfirmedMentoringCount( - isInitialized && !!accessToken && isMentor, + const { data: count, isSuccess } = useGetMentoringUncheckedCount( + isInitialized && isAuthenticated && isMentor, ); const [isModalOpen, setIsModalOpen] = useState(true); @@ -39,7 +36,14 @@ const MentorApplyCountContent = () => { > ✕ - setIsModalOpen(false)}> + ); }; diff --git a/apps/web/src/components/mentor/MentorExpandChatCard/hooks/useExpandCardClickHandler.ts b/apps/web/src/components/mentor/MentorExpandChatCard/hooks/useExpandCardClickHandler.ts index 6907ffbf..fea368a4 100644 --- a/apps/web/src/components/mentor/MentorExpandChatCard/hooks/useExpandCardClickHandler.ts +++ b/apps/web/src/components/mentor/MentorExpandChatCard/hooks/useExpandCardClickHandler.ts @@ -2,7 +2,6 @@ import { useState } from "react"; import { usePatchMenteeCheckMentorings, usePatchMentorCheckMentorings } from "@/apis/mentor"; import useAuthStore from "@/lib/zustand/useAuthStore"; import { UserRole } from "@/types/mentor"; -import { tokenParse } from "@/utils/jwtUtils"; interface UseExpandCardClickHandlerReturn { isExpanded: boolean; @@ -18,9 +17,8 @@ const useExpandCardClickHandler = ({ mentoringId, initChecked = false, }: UseExpandCardClickHandlerProps): UseExpandCardClickHandlerReturn => { - const { accessToken } = useAuthStore(); - const isMentor = - tokenParse(accessToken)?.role === UserRole.MENTOR || tokenParse(accessToken)?.role === UserRole.ADMIN; + const userRole = useAuthStore((state) => state.userRole); + const isMentor = userRole === UserRole.MENTOR; const [isExpanded, setIsExpanded] = useState(false); const [isCheckedState, setIsCheckedState] = useState(initChecked || false); From e6f74502323d6df173895632fbfae944480a45db Mon Sep 17 00:00:00 2001 From: manNomi Date: Sat, 14 Feb 2026 19:30:00 +0900 Subject: [PATCH 3/3] =?UTF-8?q?refactor:=20=E2=99=BB=EF=B8=8F=20RootModal?= =?UTF-8?q?=20=EB=AA=A8=EB=8B=AC=20=EB=A0=8C=EB=8D=94=EB=A7=81=EC=9D=84=20?= =?UTF-8?q?=ED=81=B4=EB=9D=BC=EC=9D=B4=EC=96=B8=ED=8A=B8=EB=A1=9C=20?= =?UTF-8?q?=ED=86=B5=ED=95=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- apps/web/src/components/layout/RootModal/index.tsx | 8 +------- .../components/layout/RootModal/ui/ClientModal/index.tsx | 9 ++++++--- .../components/layout/RootModal/ui/ServerModal/index.tsx | 9 --------- 3 files changed, 7 insertions(+), 19 deletions(-) delete mode 100644 apps/web/src/components/layout/RootModal/ui/ServerModal/index.tsx diff --git a/apps/web/src/components/layout/RootModal/index.tsx b/apps/web/src/components/layout/RootModal/index.tsx index 263b12c0..a6f96e12 100644 --- a/apps/web/src/components/layout/RootModal/index.tsx +++ b/apps/web/src/components/layout/RootModal/index.tsx @@ -1,13 +1,7 @@ import ClientModal from "./ui/ClientModal"; -import ServerModal from "./ui/ServerModal"; const RootModal = () => { - return ( - <> - - - - ); + return ; }; export default RootModal; diff --git a/apps/web/src/components/layout/RootModal/ui/ClientModal/index.tsx b/apps/web/src/components/layout/RootModal/ui/ClientModal/index.tsx index 14678315..83a6eb7d 100644 --- a/apps/web/src/components/layout/RootModal/ui/ClientModal/index.tsx +++ b/apps/web/src/components/layout/RootModal/ui/ClientModal/index.tsx @@ -1,5 +1,6 @@ "use client"; +import MentorApplyCountModal from "@/components/mentor/MentorApplyCountModal"; import IconConfirmModal from "@/components/modal/IconConfirmModal"; import { useConfirmModalStore } from "@/lib/zustand/useConfirmModalStore"; @@ -7,8 +8,10 @@ import { useConfirmModalStore } from "@/lib/zustand/useConfirmModalStore"; const ClientModal = () => { const { isOpen, payload, confirm, reject } = useConfirmModalStore(); - return ( + return [ + , { rejectMessage={payload?.rejectMessage || "취소"} onConfirm={confirm} onClose={reject} - /> - ); + />, + ]; }; export default ClientModal; diff --git a/apps/web/src/components/layout/RootModal/ui/ServerModal/index.tsx b/apps/web/src/components/layout/RootModal/ui/ServerModal/index.tsx deleted file mode 100644 index ba5ef93d..00000000 --- a/apps/web/src/components/layout/RootModal/ui/ServerModal/index.tsx +++ /dev/null @@ -1,9 +0,0 @@ -import MentorApplyCountModal from "@/components/mentor/MentorApplyCountModal"; -import isServerStateLogin from "@/utils/isServerStateLogin"; - -const ServerModal = () => { - // 서버에서 로그인 상태 확인 - const isServerLogin = isServerStateLogin(); - return <>{isServerLogin ? : null}; -}; -export default ServerModal;