diff --git a/src/components/common/Modal/ErrorModal.tsx b/src/components/common/Modal/ErrorModal.tsx index d145ede8..9ebc5f31 100644 --- a/src/components/common/Modal/ErrorModal.tsx +++ b/src/components/common/Modal/ErrorModal.tsx @@ -12,6 +12,7 @@ interface ErrorModalProps { showCloseButton?: boolean; children?: React.ReactNode; className?: string; + confirmText?: string; } /* 기존에 errorMessage를 props로 받았는데, @@ -24,6 +25,7 @@ const ErrorModal = ({ showCloseButton = false, children, className, + confirmText, }: ErrorModalProps) => { return ( - 확인 + {confirmText ?? '확인'} diff --git a/src/hooks/useInitUser.tsx b/src/hooks/useInitUser.tsx index fe9b8b73..b5abf129 100644 --- a/src/hooks/useInitUser.tsx +++ b/src/hooks/useInitUser.tsx @@ -7,18 +7,23 @@ import { useUserStore } from '@/stores/userStore'; * 앱 진입 시 유저 정보를 패치하고 Zustand에 저장하는 훅 */ export const useInitUser = () => { const setUser = useUserStore((state) => state.setUser); + const clearUser = useUserStore((state) => state.clearUser); + const setIsUserLoading = useUserStore((state) => state.setIsUserLoading); - /* 처음에만 실행 */ useEffect(() => { const fetchUser = async () => { + setIsUserLoading(true); // 유저 정보 불러오기 시작 + try { - const user = await getUser(); - setUser(user); + const user = await getUser(); // API 호출 + setUser(user); // 로그인 상태로 전역 상태 설정 } catch (error) { - // 로그인 안 돼있는 경우 무시 + clearUser(); // 실패 시 로그아웃 상태로 초기화 + } finally { + setIsUserLoading(false); // 로딩 끝 } }; fetchUser(); - }, [setUser]); + }, [setUser, clearUser, setIsUserLoading]); }; diff --git a/src/hooks/useUser.tsx b/src/hooks/useUser.tsx index 118a3682..83c8940c 100644 --- a/src/hooks/useUser.tsx +++ b/src/hooks/useUser.tsx @@ -5,8 +5,9 @@ import { useUserStore } from '@/stores/userStore'; export const useUser = () => { const user = useUserStore((state) => state.user); const isLoggedIn = useUserStore((state) => state.isLoggedIn); + const isUserLoading = useUserStore((state) => state.isUserLoading); const setUser = useUserStore((state) => state.setUser); const clearUser = useUserStore((state) => state.clearUser); - return { user, isLoggedIn, setUser, clearUser }; + return { user, isLoggedIn, isUserLoading, setUser, clearUser }; }; diff --git a/src/pages/my-profile/index.tsx b/src/pages/my-profile/index.tsx index 940cb7aa..51d4fda3 100644 --- a/src/pages/my-profile/index.tsx +++ b/src/pages/my-profile/index.tsx @@ -1,9 +1,14 @@ -import React, { useState } from 'react'; +import React, { useEffect, useState } from 'react'; +import { useRouter } from 'next/router'; + +import { LoadingOverlay } from '@/components/common/LoadingOverlay'; +import ErrorModal from '@/components/common/Modal/ErrorModal'; import Profile from '@/components/my-profile/Profile'; import { ReviewList } from '@/components/my-profile/ReviewList'; import { TabNav } from '@/components/my-profile/Tab'; import { WineList } from '@/components/my-profile/WineList'; +import { useUser } from '@/hooks/useUser'; /** * MyProfile @@ -15,43 +20,61 @@ import { WineList } from '@/components/my-profile/WineList'; * - 각 리스트의 총 개수를 상위에서 관리 */ export default function MyProfile() { - /** - * 현재 선택된 탭 상태 - * - 'reviews': 내가 쓴 리뷰 - * - 'wines': 내가 등록한 와인 - */ - const [tab, setTab] = useState<'reviews' | 'wines'>('reviews'); + const router = useRouter(); + const { isLoggedIn, isUserLoading } = useUser(); + const [showModal, setShowModal] = useState(false); - /** 리뷰 총 개수 (리뷰 탭에서 ReviewList가 설정함) */ + const [tab, setTab] = useState<'reviews' | 'wines'>('reviews'); const [reviewsCount, setReviewsCount] = useState(0); - - /** 와인 총 개수 (와인 탭에서 WineList가 설정함) */ const [winesCount, setWinesCount] = useState(0); + useEffect(() => { + if (!isUserLoading && !isLoggedIn) { + setShowModal(true); + } + }, [isLoggedIn, isUserLoading]); + + const handleRedirect = () => { + router.push('/signin'); // 로그인 페이지로 이동 + }; + return (
-
- {/* 프로필 섹션 */} - - - {/* 탭 + 리스트 */} -
- {/* 탭 네비게이션: 현재 탭, 탭 전환 함수, 각각의 개수 전달 */} - - - {/* 탭 상태에 따라 리스트 컴포넌트 조건부 렌더링 */} - {tab === 'reviews' ? ( - - ) : ( - - )} -
-
+ {/* 로딩 중일 때 전체 오버레이 */} + {isUserLoading && } + + {}} + onConfirm={handleRedirect} + confirmText='로그인 하러 가기' + > + 마이페이지는 로그인 후 이용할 수 있어요 + + {isLoggedIn && ( +
+ {/* 프로필 섹션 */} + + + {/* 탭 + 리스트 */} +
+ {/* 탭 네비게이션: 현재 탭, 탭 전환 함수, 각각의 개수 전달 */} + + + {/* 탭 상태에 따라 리스트 컴포넌트 조건부 렌더링 */} + {tab === 'reviews' ? ( + + ) : ( + + )} +
+
+ )}
); } diff --git a/src/stores/userStore.ts b/src/stores/userStore.ts index 3644a57f..5666fa0f 100644 --- a/src/stores/userStore.ts +++ b/src/stores/userStore.ts @@ -1,32 +1,42 @@ import { create } from 'zustand'; -/* 유저 정보 타입 */ -interface User { - id: number; - nickname: string; - image: string | null; - teamId: string; - createdAt: string; - updatedAt: string; -} +import { GetUserResponse } from '@/types/UserTypes'; /* Zustand 유저 상태 저장소 타입 */ interface UserStore { - user: User | null; + user: GetUserResponse | null; isLoggedIn: boolean; + isUserLoading: boolean; /* 유저 정보 설정 (로그인 등) */ - setUser: (user: User) => void; + setUser: (user: GetUserResponse) => void; /* 유저 정보 초기화 (로그아웃 등) */ clearUser: () => void; + + /* 유저 정보 로딩 상태 변경 */ + setIsUserLoading: (loading: boolean) => void; } /** - * 유저 상태 전역 스토어 */ + * 유저 상태 전역 스토어 + */ export const useUserStore = create((set) => ({ user: null, isLoggedIn: false, - setUser: (user) => set({ user, isLoggedIn: true }), - clearUser: () => set({ user: null, isLoggedIn: false }), + isUserLoading: true, + + setUser: (user) => + set({ + user, + isLoggedIn: true, + }), + + clearUser: () => + set({ + user: null, + isLoggedIn: false, + }), + + setIsUserLoading: (loading) => set({ isUserLoading: loading }), }));