From 85d0a1146cfbf1fe13ecf72d23a9b20c552979a7 Mon Sep 17 00:00:00 2001 From: JAEMOON Date: Sun, 22 Oct 2023 20:10:43 +0900 Subject: [PATCH] =?UTF-8?q?[feat]=20my=20Profile=20Api=20=EC=97=B0?= =?UTF-8?q?=EB=8F=99!!!?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- api/userInfo.ts | 11 ++++++++ components/Nav/Nav.tsx | 22 ++++++++++++---- components/ProfileCard/index.tsx | 2 +- context/UserInfoProvider.tsx | 45 ++++++++++++++++++++++++++++++++ hooks/useUserInfo.ts | 20 ++++++++++++++ pages/_app.tsx | 15 ++++++----- pages/index.tsx | 21 ++++++++++++--- pages/login.tsx | 16 ++++++++++++ pages/userInfo/index.tsx | 4 +-- 9 files changed, 139 insertions(+), 17 deletions(-) create mode 100644 api/userInfo.ts create mode 100644 context/UserInfoProvider.tsx create mode 100644 hooks/useUserInfo.ts diff --git a/api/userInfo.ts b/api/userInfo.ts new file mode 100644 index 0000000..57a4e60 --- /dev/null +++ b/api/userInfo.ts @@ -0,0 +1,11 @@ +import { UserInfoProps } from '../context/UserInfoProvider.tsx'; +import { fetchData } from '.'; + +export const getProfile = async () => { + return fetchData('/api/v1/my', { + method: 'GET', + headers: { + 'Content-Type': 'application/json', + }, + }); +}; diff --git a/components/Nav/Nav.tsx b/components/Nav/Nav.tsx index ff34006..e100ece 100644 --- a/components/Nav/Nav.tsx +++ b/components/Nav/Nav.tsx @@ -1,8 +1,10 @@ -import React, { useState } from 'react'; +import React, { useEffect, useState } from 'react'; import Like from '@/public/icons/like.svg'; import Home from '@/public/icons/home.svg'; import Me from '@/public/icons/me.svg'; import { useRouter } from 'next/router'; +import useUserInfo from '@/hooks/useUserInfo.ts'; +import { UserInfoProps } from '@/context/UserInfoProvider.tsx'; import styles from './Nav.module.scss'; const defaultStrokeColor = 'stroke-g4 stroke-[1.5px]'; @@ -10,8 +12,8 @@ const activeStrokeColor = 'stroke-r1 stroke-[1.5px]'; interface NavProps { initMenu?: number; + profile?: UserInfoProps; } - const menus = [ { name: 'Rooms', @@ -30,14 +32,24 @@ const menus = [ }, ]; -export default function Nav({ initMenu }: NavProps) { +export default function Nav({ initMenu, profile }: NavProps) { const [hoverMenu, setHoverMenu] = useState(-1); // 초기화 const router = useRouter(); - + const { setUserInfoData, userInfoState } = useUserInfo(); const handleNavClicked = (index: number) => { - router.push(menus[index].router); + router.push( + { + pathname: menus[index].router, + query: { data: profile && JSON.stringify(profile) }, + }, + `${menus[index].router}` + ); }; + useEffect(() => { + console.log('userInfoData in Nav', profile); + }, [profile]); + return (
{menus.map((menu, index) => { diff --git a/components/ProfileCard/index.tsx b/components/ProfileCard/index.tsx index ce0953b..931ebad 100644 --- a/components/ProfileCard/index.tsx +++ b/components/ProfileCard/index.tsx @@ -113,7 +113,7 @@ export default function ProfileCard({ name, age, gender, imageSrc }: ProfileCard
- {`${name}'s + {'
{name}
diff --git a/context/UserInfoProvider.tsx b/context/UserInfoProvider.tsx new file mode 100644 index 0000000..a3f4a9e --- /dev/null +++ b/context/UserInfoProvider.tsx @@ -0,0 +1,45 @@ +import React, { useState, useMemo } from 'react'; + +interface ComponentProps { + children: React.ReactNode; +} + +export interface UserInfoProps { + id?: number; + email?: string; + firstName?: string; + lastName?: string; + gender?: string; + birthDate?: string; + description?: string; + imageFile?: { + deleted?: boolean; + createdAt?: string; + updatedAt?: string; + id?: number; + path?: string; + size?: number; + }; + userRole?: string; + signUpStatus?: string; +} + +interface SetterProps { + setState: React.Dispatch>; +} + +export const UserInfoStateContext = React.createContext(null); +export const UserInfoSetterContext = React.createContext(null); + +export default function UserInfoProvider({ children }: ComponentProps) { + const [state, setState] = useState({}); + + const memoizedSetterValue = useMemo(() => ({ setState }), [setState]); + const memoizedStateValue = useMemo(() => state, [state]); + + return ( + + {children} + + ); +} diff --git a/hooks/useUserInfo.ts b/hooks/useUserInfo.ts new file mode 100644 index 0000000..0b67c8c --- /dev/null +++ b/hooks/useUserInfo.ts @@ -0,0 +1,20 @@ +import { useContext } from 'react'; +import { UserInfoSetterContext, UserInfoStateContext, UserInfoProps } from '../context/UserInfoProvider.tsx'; + +export default function useUserInfo() { + const setUserInfoState = useContext(UserInfoSetterContext); + const userInfoState = useContext(UserInfoStateContext); + if (!setUserInfoState) { + throw new Error('UserInfoSetterContext is not properly initialized'); + } + + const setUserInfoData = (data: UserInfoProps) => { + if (setUserInfoState) { + setUserInfoState.setState((userInfoData) => { + return { ...userInfoData, ...data }; + }); + } + }; + + return { setUserInfoData, userInfoState }; +} diff --git a/pages/_app.tsx b/pages/_app.tsx index 5440478..8e8371b 100644 --- a/pages/_app.tsx +++ b/pages/_app.tsx @@ -9,6 +9,7 @@ import dynamic from 'next/dynamic'; import Providers from '@/context/Providers.tsx'; import { SessionProvider, getSession } from 'next-auth/react'; import { Session } from 'next-auth'; +import UserInfoProvider from '@/context/UserInfoProvider.tsx'; import ModalProvider from '../context/ModalProvider.tsx'; import ModalContainer from '../components/Modal/ModalContainer.tsx'; import AppLayout from '../components/layouts/AppLayout/AppLayout.tsx'; @@ -70,12 +71,14 @@ function MyApp({ Component, pageProps }: LayoutAppProps): React.ReactElement { - {data && ( - - {getLayout()} - - - )} + + {data && ( + + {getLayout()} + + + )} + diff --git a/pages/index.tsx b/pages/index.tsx index ca4c9b6..9804f70 100644 --- a/pages/index.tsx +++ b/pages/index.tsx @@ -13,6 +13,9 @@ import { FieldValues } from 'react-hook-form'; import Filter from '@/components/Filter/Filter.tsx'; import { getRooms } from '@/api/room'; import isEmpty from 'lodash-es/isEmpty'; +import useUserInfo from '@/hooks/useUserInfo.ts'; +import { getProfile } from '@/api/userInfo'; +import { UserInfoProps } from '@/context/UserInfoProvider.tsx'; type HomeProps = NextPage & { getLayout: (page: React.ReactElement, ctx: NextPageContext) => React.ReactNode; @@ -29,6 +32,7 @@ const FILTER_LABEL: Record = { function Home() { const [rooms, setRooms] = useState([]); + const [profile, setProfile] = useState(); const [filters, setFilters] = useState([]); const [clickedChip, setClickedChip] = useState(''); const router = useRouter(); @@ -36,7 +40,7 @@ function Home() { const [page, setPage] = useState(0); const [totalElements, setTotalElements] = useState(0); const [searchParams, setSearchParams] = useState>({}); - + const { setUserInfoData, userInfoState } = useUserInfo(); // TODO: 전체 페이지보다 크면 페이징 처리 안되도록 수정 // TODO : ModalLayer 로 로그인한 사용자의 Context 생성 필요 const selectRooms = async () => { @@ -70,7 +74,17 @@ function Home() { setSearchParams(childData); setRooms([]); }; - + const selectProfile = async () => { + try { + const data = await getProfile(); + if (data != null) { + console.log('data info userProfile', data); + setProfile(data); + } + } catch (error) { + console.error(error); + } + }; const openFilterPopup = () => { openModal({ props: { @@ -112,6 +126,7 @@ function Home() { useEffect(() => { (async () => { await selectRooms(); + await selectProfile(); if (target?.current) { const observer = new IntersectionObserver(callback, options); observer.observe(target.current); @@ -197,7 +212,7 @@ function Home() {
-
diff --git a/pages/login.tsx b/pages/login.tsx index 822cdd3..e8174d9 100644 --- a/pages/login.tsx +++ b/pages/login.tsx @@ -8,6 +8,8 @@ import { LoginLayout, Link, CustomImage, Chip, Button, Input, Space } from '@/co import { isRequired, isValidEmail, isValidPassword } from '@/utils/validCheck.ts'; import { login } from '@/api/signup'; import { signIn } from 'next-auth/react'; +import { getProfile } from '@/api/userInfo'; +import useUserInfo from '@/hooks/useUserInfo.ts'; export const getStaticProps = async ({ locale }: GetStaticPropsContext) => ({ props: { @@ -17,6 +19,7 @@ export const getStaticProps = async ({ locale }: GetStaticPropsContext) => ({ export default function Login() { const { t } = useTranslation('common'); + const { setUserInfoData, userInfoState } = useUserInfo(); const { handleSubmit, register, @@ -27,7 +30,20 @@ export default function Login() { const email = watch('email'); const password = watch('password'); + const selectProfile = async () => { + try { + const data = await getProfile(); + if (data != null) { + console.log('data info userProfile', data); + setUserInfoData(data); + } + } catch (error) { + console.error(error); + } + }; + const onSubmit = async () => { + await selectProfile(); await signIn('email-password-credential', { email, password, diff --git a/pages/userInfo/index.tsx b/pages/userInfo/index.tsx index 6069ac1..5aaf762 100644 --- a/pages/userInfo/index.tsx +++ b/pages/userInfo/index.tsx @@ -11,10 +11,10 @@ export default function UserProfile({ imgSrc }: UserProfileProps) { const router = useRouter(); const { query } = router; const userInfo = query.data ? JSON.parse(query.data as string) : {}; - const age = formatAge(userInfo.year); + const age = formatAge(userInfo.birthDate); return ( <> - +