From a19cbb82e0085adcf44b6f05d08402417f143498 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=EC=A1=B0=EC=88=98=EB=AF=BC?= Date: Wed, 26 Jun 2024 17:35:03 +0900 Subject: [PATCH] =?UTF-8?q?feat:=20=EB=A7=88=EC=9D=B4=ED=8E=98=EC=9D=B4?= =?UTF-8?q?=EC=A7=80=20=EB=A6=AC=ED=8C=A9=ED=86=A0=EB=A7=81=20(#222)?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit * refactor: 하단에 hidden component를 추가하여 relative하게 중앙 정렬 * feat: 마이페이지에 계정 탈퇴 메뉴 추가 * refactor: useQuery로 api 호출 방식 변경 * feat: privateRoute hooks 구현 * feat: Nav Bar 로그아웃 기능 추가 * refactor: privateRoute에서 로그아웃 후 login 페이지로 이동하는 방식으로 변경 * refactor: PrivateRoute outlet 중첩 라우팅으로 수정 * fix: 기존에 userState 사용하는 로직 삭제, resetUserInfo 적용 * refactor: useQuery에서 useMutation으로 변경, useCurrentPasswordForm 내부로 위치 변경 * fix: resetUserInfo 중복 선언 제거 * fix: PrivateRoute 적용 페이지 추가 --- src/home/apis/getUserPasswordMatch.ts | 29 ++++------------ .../ChangePasswordFrame.style.ts | 17 ++++++---- .../ChangePasswordFrame.tsx | 5 +++ .../CurrentPasswordForm.tsx | 6 ++-- .../useCurrentPasswordForm.ts | 34 +++++++++++-------- src/home/components/Dialog/LogoutModal.tsx | 2 +- src/home/components/MyMenuList/MyMenuList.tsx | 1 + src/hooks/usePrivateRoute.tsx | 24 +++++++++++++ src/router.tsx | 21 ++++++++---- 9 files changed, 84 insertions(+), 55 deletions(-) create mode 100644 src/hooks/usePrivateRoute.tsx diff --git a/src/home/apis/getUserPasswordMatch.ts b/src/home/apis/getUserPasswordMatch.ts index 375b0769..c087876c 100644 --- a/src/home/apis/getUserPasswordMatch.ts +++ b/src/home/apis/getUserPasswordMatch.ts @@ -1,26 +1,11 @@ -import { AxiosError } from 'axios'; - import { authClient } from '@/apis'; -import { AuthErrorData } from '@/home/types/Auth.type'; -import { GetPasswordResponse } from '@/home/types/password.type'; +import { SessionTokenType } from '@/home/types/password.type'; import { api } from '@/service/TokenService'; -interface getPasswordProps { - password: string; -} - -export const getUserPasswordMatch = async ( - props: getPasswordProps -): Promise => { - const { password } = props; - - try { - const res = await authClient.get('/auth/verification/password', { - params: { password }, - headers: api.headers, - }); - return { data: res.data }; - } catch (error: unknown) { - return { error: error as AxiosError }; - } +export const getUserPasswordMatch = async (password: string): Promise => { + const res = await authClient.get('/auth/verification/password', { + params: { password }, + headers: api.headers, + }); + return res.data; }; diff --git a/src/home/components/ChangePasswordContents/ChangePasswordFrame/ChangePasswordFrame.style.ts b/src/home/components/ChangePasswordContents/ChangePasswordFrame/ChangePasswordFrame.style.ts index cce41b4f..7620b90b 100644 --- a/src/home/components/ChangePasswordContents/ChangePasswordFrame/ChangePasswordFrame.style.ts +++ b/src/home/components/ChangePasswordContents/ChangePasswordFrame/ChangePasswordFrame.style.ts @@ -2,25 +2,28 @@ import { Link } from 'react-router-dom'; import styled from 'styled-components'; export const StyledChangePasswordFrame = styled.div` - flex: 1; - display: flex; flex-direction: column; justify-content: center; align-items: center; gap: 24px; +`; - margin-bottom: 101px; +export const StyledLink = styled(Link)``; + +export const StyledHiddenDiv = styled.div` + transform: rotate(180deg); + visibility: hidden; `; -export const StyledLink = styled(Link)` +export const StyledLogo = styled.img` width: 180px; height: 29px; `; -export const StyledLogo = styled.img` - width: 100%; - height: 100%; +export const StyledHiddenLogo = styled.img` + width: 180px; + height: 29px; `; export const StyledContainer = styled.div` diff --git a/src/home/components/ChangePasswordContents/ChangePasswordFrame/ChangePasswordFrame.tsx b/src/home/components/ChangePasswordContents/ChangePasswordFrame/ChangePasswordFrame.tsx index 4081fe00..2d5f3c3c 100644 --- a/src/home/components/ChangePasswordContents/ChangePasswordFrame/ChangePasswordFrame.tsx +++ b/src/home/components/ChangePasswordContents/ChangePasswordFrame/ChangePasswordFrame.tsx @@ -5,6 +5,8 @@ import { StyledContainer, StyledLink, StyledLogo, + StyledHiddenLogo, + StyledHiddenDiv, } from './ChangePasswordFrame.style'; interface ChangePasswordFrameProps { @@ -18,6 +20,9 @@ export const ChangePasswordFrame = ({ children }: ChangePasswordFrameProps) => { {children} + + + ); }; diff --git a/src/home/components/ChangePasswordContents/CurrentPasswordForm/CurrentPasswordForm.tsx b/src/home/components/ChangePasswordContents/CurrentPasswordForm/CurrentPasswordForm.tsx index d54e9ce5..81152081 100644 --- a/src/home/components/ChangePasswordContents/CurrentPasswordForm/CurrentPasswordForm.tsx +++ b/src/home/components/ChangePasswordContents/CurrentPasswordForm/CurrentPasswordForm.tsx @@ -18,7 +18,7 @@ interface CurrentPasswordFormProps { } export const CurrentPasswordForm = (props: CurrentPasswordFormProps) => { - const { currentPassword, isError, handlePasswordChange, checkCurrentPassword } = + const { currentPassword, isPasswordError, handlePasswordChange, checkCurrentPassword } = useCurrentPasswordForm(props); return ( @@ -30,8 +30,8 @@ export const CurrentPasswordForm = (props: CurrentPasswordFormProps) => { placeholder="비밀번호를 입력해주세요." value={currentPassword} onChange={(e) => handlePasswordChange(e.target.value)} - isNegative={isError} - helperLabel={isError ? '비밀번호가 일치하지 않습니다.' : ''} + isNegative={isPasswordError} + helperLabel={isPasswordError ? '비밀번호가 일치하지 않습니다.' : ''} /> diff --git a/src/home/components/ChangePasswordContents/CurrentPasswordForm/useCurrentPasswordForm.ts b/src/home/components/ChangePasswordContents/CurrentPasswordForm/useCurrentPasswordForm.ts index 9c62b2fd..9844529d 100644 --- a/src/home/components/ChangePasswordContents/CurrentPasswordForm/useCurrentPasswordForm.ts +++ b/src/home/components/ChangePasswordContents/CurrentPasswordForm/useCurrentPasswordForm.ts @@ -1,5 +1,6 @@ import { useState } from 'react'; +import { useMutation } from '@tanstack/react-query'; import { useNavigate } from 'react-router-dom'; import { useRecoilValue } from 'recoil'; @@ -18,37 +19,40 @@ export const useCurrentPasswordForm = ({ setSessionToken, setPreviousPassword, }: CurrentPasswordFormProps) => { - const [currentPassword, setCurrentPassword] = useState(''); - const [isError, setIsError] = useState(false); + const [currentPassword, setCurrentPassword] = useState(''); + const [isPasswordError, setIsPasswordError] = useState(false); const isLoggedIn = useRecoilValue(LogInState); const navigate = useNavigate(); - const checkCurrentPassword = async () => { + const passwordMatchMutation = useMutation({ + mutationFn: getUserPasswordMatch, + onSuccess: (data) => { + setSessionToken(data); + setPreviousPassword(currentPassword); + onConfirm(); + }, + onError: () => { + setIsPasswordError(true); + }, + }); + + const checkCurrentPassword = () => { if (!isLoggedIn) { navigate('/Login'); return; } - const { error, data } = await getUserPasswordMatch({ - password: currentPassword, - }); - - if (data) { - setIsError(false); - setSessionToken(data as SessionTokenType); - setPreviousPassword(currentPassword); - onConfirm(); - } else if (error) setIsError(true); + passwordMatchMutation.mutate(currentPassword); }; const handlePasswordChange = (password: string) => { - if (isError) setIsError(false); + if (isPasswordError) setIsPasswordError(false); setCurrentPassword(password); }; return { currentPassword, - isError, + isPasswordError, handlePasswordChange, checkCurrentPassword, }; diff --git a/src/home/components/Dialog/LogoutModal.tsx b/src/home/components/Dialog/LogoutModal.tsx index 448f6654..d174b00f 100644 --- a/src/home/components/Dialog/LogoutModal.tsx +++ b/src/home/components/Dialog/LogoutModal.tsx @@ -20,8 +20,8 @@ interface LogoutModalProps { } export const LogoutModal = ({ open, onOpenChange }: LogoutModalProps) => { - const navigate = useNavigate(); const resetUserInfo = useResetUserInfo(); + const navigate = useNavigate(); const handleLogout = () => { resetUserInfo(); diff --git a/src/home/components/MyMenuList/MyMenuList.tsx b/src/home/components/MyMenuList/MyMenuList.tsx index 7cbecb43..a44a362a 100644 --- a/src/home/components/MyMenuList/MyMenuList.tsx +++ b/src/home/components/MyMenuList/MyMenuList.tsx @@ -34,6 +34,7 @@ export const MyMenuList = () => { navigate('/changePassword')}> 비밀번호 변경 + navigate('/withdraw')}>계정탈퇴 setIsOpenModal(true)}>로그아웃 diff --git a/src/hooks/usePrivateRoute.tsx b/src/hooks/usePrivateRoute.tsx new file mode 100644 index 00000000..34821d9e --- /dev/null +++ b/src/hooks/usePrivateRoute.tsx @@ -0,0 +1,24 @@ +import { Navigate, Outlet } from 'react-router-dom'; +import { useRecoilValue } from 'recoil'; + +import { LogInState } from '@/home/recoil/LogInState'; +import { api } from '@/service/TokenService'; + +import { useResetUserInfo } from './useResetUserInfo'; + +export const usePrivateRoute = () => { + const isLoggedIn = useRecoilValue(LogInState); + const accessToken = api.getAccessToken(); + + const resetUserInfo = useResetUserInfo(); + + const PrivateRoute = (): React.ReactNode => { + if (!isLoggedIn || !accessToken) { + resetUserInfo(); + return ; + } + return ; + }; + + return { PrivateRoute }; +}; diff --git a/src/router.tsx b/src/router.tsx index fbc6dd6a..23994999 100644 --- a/src/router.tsx +++ b/src/router.tsx @@ -5,6 +5,7 @@ import { Navigate, Route, Routes } from 'react-router-dom'; import { Fallback } from '@/components/Fallback/Fallback'; import { ProgressBar } from '@/components/ProgressBar/ProgressBar'; +import { usePrivateRoute } from '@/hooks/usePrivateRoute'; const Search = lazy(() => import('./search/pages/Search/Search').then(({ Search }) => ({ @@ -112,6 +113,8 @@ export const Router = () => { }; }, []); + const { PrivateRoute } = usePrivateRoute(); + return ( }> { }> }> - }> - } /> - } /> - }> - }> + }> + }> + }> + }> + }> + }> + }> }> } /> } /> - } /> - } /> + }> + } /> + } /> + } /> } /> } />