diff --git a/src/app/(AppBarHeader)/layout.tsx b/src/app/(AppBarHeader)/layout.tsx index ce63ca6e..7c340d27 100644 --- a/src/app/(AppBarHeader)/layout.tsx +++ b/src/app/(AppBarHeader)/layout.tsx @@ -1,12 +1,12 @@ import { Appbar } from './_components/Appbar'; -import { CategoryBottomSheet } from './toks-main/_components/CategoryBottomSheet'; export default function AppBarLayout({ children }: StrictPropsWithChildren) { return ( <> {children} - + {/* TODO: 에러 고치기 .. */} + {/* */} ); } diff --git a/src/app/(BackHeader)/my-page/@toast/page.tsx b/src/app/(BackHeader)/my-page/@toast/page.tsx new file mode 100644 index 00000000..7b76c587 --- /dev/null +++ b/src/app/(BackHeader)/my-page/@toast/page.tsx @@ -0,0 +1,33 @@ +'use client'; + +import React, { useEffect, useState } from 'react'; + +import { useToast } from '@/common'; +import { Toast as ToastComponent, ToastProps } from '@/common/components/Toast'; + +const Toast = () => { + const { getSavedToastInfo, clearSavedToast } = useToast(); + const [toastData, setToastData] = useState(null); + + useEffect(() => { + setToastData(getSavedToastInfo()); + + clearSavedToast(); + // eslint-disable-next-line react-hooks/exhaustive-deps + }, []); + + if (toastData === null) { + return null; + } + + return ( + + ); +}; + +export default Toast; diff --git a/src/app/(BackHeader)/my-page/@userInfo/page.tsx b/src/app/(BackHeader)/my-page/@userInfo/page.tsx new file mode 100644 index 00000000..4c29c4fd --- /dev/null +++ b/src/app/(BackHeader)/my-page/@userInfo/page.tsx @@ -0,0 +1,53 @@ +'use client'; + +import { getCookie } from 'cookies-next'; +import Image from 'next/image'; +import { useRouter } from 'next/navigation'; + +import { ICON_URL } from '@/common'; +import { Text } from '@/common/components/Text'; + +import { SkeletonUserInfo } from '../_components/SkeletonUserInfo.tsx'; +import { useSuspenseUserInfoQuery } from '../_lib/hooks/useSuspenseUserInfoQuery'; + +const UserInfo = () => { + const router = useRouter(); + const accessToken = getCookie('accessToken'); + const { data: userInfo } = useSuspenseUserInfoQuery(accessToken as string); + + if (!userInfo) { + return ; + } + return ( +
+
+ 프로필 이미지 +
+
+ + {userInfo?.nickname} + + 닉네임 수정 버튼 router.push('/nickname/update')} + /> +
+
+ + {userInfo?.email} + +
+
+ ); +}; + +export default UserInfo; diff --git a/src/app/(BackHeader)/my-page/_components/GoogleFormButton/index.tsx b/src/app/(BackHeader)/my-page/_components/GoogleFormButton/index.tsx new file mode 100644 index 00000000..11ef2703 --- /dev/null +++ b/src/app/(BackHeader)/my-page/_components/GoogleFormButton/index.tsx @@ -0,0 +1,23 @@ +'use client'; +import { useRouter } from 'next/navigation'; + +import { GOOGLE_FORM_URL } from '@/common'; +import { Button } from '@/common/components/Button'; + +export const GoogleFormButton = () => { + const router = useRouter(); + + return ( + + ); +}; diff --git a/src/app/(BackHeader)/my-page/_components/SkeletonUserInfo.tsx/index.tsx b/src/app/(BackHeader)/my-page/_components/SkeletonUserInfo.tsx/index.tsx new file mode 100644 index 00000000..dc7c1655 --- /dev/null +++ b/src/app/(BackHeader)/my-page/_components/SkeletonUserInfo.tsx/index.tsx @@ -0,0 +1,23 @@ +import Image from 'next/image'; + +import { ICON_URL } from '@/common'; +import { Skeleton } from '@/common/components/Skeleton'; + +export const SkeletonUserInfo = () => { + return ( +
+
+ 프로필 이미지 +
+
+ + +
+
+ ); +}; diff --git a/src/app/(BackHeader)/my-page/_components/UserInfo/index.tsx b/src/app/(BackHeader)/my-page/_components/UserInfo/index.tsx deleted file mode 100644 index 455dd237..00000000 --- a/src/app/(BackHeader)/my-page/_components/UserInfo/index.tsx +++ /dev/null @@ -1,45 +0,0 @@ -'use client'; - -import Image from 'next/image'; -import { useRouter } from 'next/navigation'; -import { useEffect, useState } from 'react'; - -import { ICON_URL, IMAGE_URL } from '@/common'; -import { Text } from '@/common/components/Text'; -import { useAuth } from '@/common/hooks'; - -export const UserInfo = () => { - const { user } = useAuth(); - const [profileImage, setProfileImage] = useState(ICON_URL.EMOJI_BASE_GRAY); - const router = useRouter(); - - useEffect(() => { - if (user && user.profileImageUrl !== IMAGE_URL.BASE_KAKAO) { - setProfileImage(user.profileImageUrl); - } - }, [user]); - - return ( -
-
- 프로필 이미지 -
-
- - {user?.nickname} - - 닉네임 수정 버튼 router.push('/nickname/update')} - /> -
- - {user?.email} - -
- ); -}; diff --git a/src/app/(BackHeader)/my-page/_lib/hooks/useSuspenseUserInfoQuery.ts b/src/app/(BackHeader)/my-page/_lib/hooks/useSuspenseUserInfoQuery.ts new file mode 100644 index 00000000..d0b8df1e --- /dev/null +++ b/src/app/(BackHeader)/my-page/_lib/hooks/useSuspenseUserInfoQuery.ts @@ -0,0 +1,10 @@ +import { useSuspenseQuery } from '@tanstack/react-query'; + +import { getUserInfo } from '@/common'; + +export const useSuspenseUserInfoQuery = (accessToken?: string) => { + return useSuspenseQuery({ + queryKey: ['userInfo', accessToken], + queryFn: getUserInfo, + }); +}; diff --git a/src/app/(BackHeader)/my-page/layout.tsx b/src/app/(BackHeader)/my-page/layout.tsx new file mode 100644 index 00000000..1fd55e87 --- /dev/null +++ b/src/app/(BackHeader)/my-page/layout.tsx @@ -0,0 +1,22 @@ +import React, { PropsWithChildren, Suspense } from 'react'; + +import { SkeletonUserInfo } from './_components/SkeletonUserInfo.tsx'; + +type Props = { + toast: React.ReactNode; + userInfo: React.ReactNode; +}; + +export default function MyPageLayout({ + children, + toast, + userInfo, +}: PropsWithChildren) { + return ( + <> + }>{userInfo} + {children} + {toast} + + ); +} diff --git a/src/app/(BackHeader)/my-page/page.tsx b/src/app/(BackHeader)/my-page/page.tsx index 1198ee5a..82ffbcca 100644 --- a/src/app/(BackHeader)/my-page/page.tsx +++ b/src/app/(BackHeader)/my-page/page.tsx @@ -1,39 +1,15 @@ -'use client'; import Image from 'next/image'; -import { useRouter } from 'next/navigation'; -import { useEffect, useState } from 'react'; -import { GOOGLE_FORM_URL, ICON_URL } from '@/common'; -import { Button } from '@/common/components/Button'; +import { ICON_URL } from '@/common'; import { Text } from '@/common/components/Text'; -import { Toast, ToastProps } from '@/common/components/Toast'; -import { useToast } from '@/common/hooks/useToast'; +import { GoogleFormButton } from './_components/GoogleFormButton'; import { LogoutBar } from './_components/LogoutBar'; -import { UserInfo } from './_components/UserInfo'; const MyPage = () => { - const [toastData, setToastData] = useState(null); - const router = useRouter(); - const { getSavedToastInfo, clearSavedToast } = useToast(); - useEffect(() => { - setToastData(getSavedToastInfo()); - clearSavedToast(); - // eslint-disable-next-line react-hooks/exhaustive-deps - }, []); - return (
- {toastData && ( - - )} -
@@ -47,17 +23,7 @@ const MyPage = () => { height={160} alt="로켓 이미지" /> - +
); diff --git a/src/common/utils/http.ts b/src/common/utils/http.ts index bc215e25..147ab65f 100644 --- a/src/common/utils/http.ts +++ b/src/common/utils/http.ts @@ -92,6 +92,9 @@ export const authToken = { export const redirectToLoginPage = () => { const isDev = process.env.NODE_ENV === 'development'; + if (typeof window === 'undefined') { + return; + } window.location.href = isDev ? 'http://localhost:3000/toks-main'