From 16049c6c8352fe678d34d91aa0c59713984c028a Mon Sep 17 00:00:00 2001 From: Jun99uu_Lee Date: Mon, 16 Oct 2023 18:40:21 +0900 Subject: [PATCH] feat: Add login handler + auto login handler --- client/src/apis/auth.ts | 23 +++++++++++ client/src/atoms/authInfoState.ts | 60 +++-------------------------- client/src/constants/queryKey.ts | 3 ++ client/src/hooks/index.tsx | 2 + client/src/hooks/useAuth.tsx | 52 ++++++++++++++++++++++--- client/src/pages/_app.tsx | 17 +++++--- client/src/pages/login.tsx | 30 ++++++++++++--- client/src/utils/lib/infoHandler.ts | 39 +++++++++++++++++++ 8 files changed, 155 insertions(+), 71 deletions(-) create mode 100644 client/src/apis/auth.ts create mode 100644 client/src/constants/queryKey.ts create mode 100644 client/src/utils/lib/infoHandler.ts diff --git a/client/src/apis/auth.ts b/client/src/apis/auth.ts new file mode 100644 index 0000000..3fb8796 --- /dev/null +++ b/client/src/apis/auth.ts @@ -0,0 +1,23 @@ +import { AuthData, AuthResponse } from 'Auth'; +import axios, { AxiosResponse } from 'axios'; + +class AuthApi { + /** 로그인 */ + login = async (loginId: string, password: string): Promise => { + const data: AxiosResponse = await axios({ + method: 'post', + url: `${process.env.NEXT_PUBLIC_BASE_URL}/login`, + headers: { + 'Content-Type': 'application/json', + }, + data: { + loginId, + password, + }, + }); + + return data.data.data; + }; +} + +export default AuthApi; diff --git a/client/src/atoms/authInfoState.ts b/client/src/atoms/authInfoState.ts index 54802ba..f6ccaf8 100644 --- a/client/src/atoms/authInfoState.ts +++ b/client/src/atoms/authInfoState.ts @@ -1,58 +1,8 @@ -import { AuthResponse } from 'Auth'; import { atom } from 'jotai'; -export const authInfoState = atom(null); - -export const dummyAuthData: AuthResponse = { - success: true, - code: 'successCode_xyz123', - message: '로그인되었습니다.', - data: { - availableHomepages: [42, 69], - isPrivacyPolicyAgree: true, - privacyPolicyAgreePeriod: 3, - dept: { - id: 456, - code: 'deptCode_abc789', - name: '과학학부', - }, - accessToken: 'xyzabc789ghi', - parentDept: { - id: 457, - code: 'parentDeptCode_def456', - name: '자연대학', - }, - branch: { - id: 123, - name: '서부도서관', - alias: '서부', - libraryCode: 'libCode_ghi123', - sortOrder: 2, - }, - showMobileMain: false, - memberNo: 'member_xyz789', - alternativeId: 'altid_ghi123', - lastUpdated: '2023-07-27 15:23:45', - branchGroup: { - id: 24, - name: '서울대학교', - }, - isPortalLogin: false, - patronType: { - id: 34, - name: '교수', - }, - disableServices: ['ABC', 'DEF', 'GHI'], - hasFamily: false, - name: '홍길동', - printMemberNo: 'print_xyz456', - patronState: { - id: 789, - name: '퇴직', - }, - id: 987, - multiTypePatrons: [], - isExpired: false, - isFamilyLogin: false, - }, +export type authInfoType = { + name: string; + sId: string; }; + +export const authInfoState = atom(null); diff --git a/client/src/constants/queryKey.ts b/client/src/constants/queryKey.ts new file mode 100644 index 0000000..0e70367 --- /dev/null +++ b/client/src/constants/queryKey.ts @@ -0,0 +1,3 @@ +export const QUERY_KEYS = { + login: 'LOGIN', +}; diff --git a/client/src/hooks/index.tsx b/client/src/hooks/index.tsx index e86ae8f..f6a181b 100644 --- a/client/src/hooks/index.tsx +++ b/client/src/hooks/index.tsx @@ -1,2 +1,4 @@ export { default as useVh } from './useVh'; export { default as useHeader } from './useHeader'; +export { default as useInput } from './useInput'; +export { default as useAuth } from './useAuth'; diff --git a/client/src/hooks/useAuth.tsx b/client/src/hooks/useAuth.tsx index 9d3e75f..2361d2b 100644 --- a/client/src/hooks/useAuth.tsx +++ b/client/src/hooks/useAuth.tsx @@ -1,20 +1,62 @@ +import AuthApi from '@/apis/auth'; import { authInfoState } from '@/atoms/authInfoState'; +import { getUserInfo, updateUserInfo } from '@/utils/lib/infoHandler'; +import { updateAccessToken } from '@/utils/lib/tokenHandler'; import { useAtom } from 'jotai'; import { useRouter } from 'next/router'; const useAuth = () => { + const authApi = new AuthApi(); + const router = useRouter(); const [authInfo, setAuthInfo] = useAtom(authInfoState); - const handleLogin = () => { - router.replace('/'); + /** + * 로그인 함수 + */ + const handleLogin = async (id: string, password: string) => { + try { + const data = await authApi.login(id, password); + console.log(data); + setAuthInfo({ + name: data.name, + sId: data.printMemberNo, + }); + updateAccessToken(data.accessToken); + updateUserInfo(data.name, data.printMemberNo, id, password); + router.replace('/'); + } catch (err) { + console.log(err); + } }; - const checkAuth = () => { - if (!authInfo) router.replace('/landing'); + /** + * 자동 로그인 함수 + */ + const autoLogin = async () => { + try { + const userInfo = getUserInfo(); + if (!userInfo) throw new Error('Empty user info'); + const data = await authApi.login(userInfo.loginId, userInfo.password); + console.log(data); + setAuthInfo({ + name: data.name, + sId: data.printMemberNo, + }); + updateAccessToken(data.accessToken); + updateUserInfo( + data.name, + data.printMemberNo, + userInfo.loginId, + userInfo.password, + ); + } catch (err) { + console.log(err); + router.replace('/landing'); + } }; - return { authInfo, checkAuth, handleLogin }; + return { authInfo, autoLogin, handleLogin }; }; export default useAuth; diff --git a/client/src/pages/_app.tsx b/client/src/pages/_app.tsx index a17f511..ce88842 100644 --- a/client/src/pages/_app.tsx +++ b/client/src/pages/_app.tsx @@ -7,9 +7,12 @@ import { Global, css } from '@emotion/react'; import reset from '@/styles/reset'; import { useRouter } from 'next/router'; import { COLORS } from '@/styles/colors'; +import { QueryClient, QueryClientProvider } from '@tanstack/react-query'; + +const queryClient = new QueryClient(); export default function App({ Component, pageProps }: AppProps) { - const { checkAuth } = useAuth(); + const { autoLogin } = useAuth(); const router = useRouter(); const getBgColor = (pathname: string) => { @@ -22,14 +25,16 @@ export default function App({ Component, pageProps }: AppProps) { }; useEffect(() => { - checkAuth(); + autoLogin(); }, []); return ( - - - - + + + + + + ); } diff --git a/client/src/pages/login.tsx b/client/src/pages/login.tsx index aa514e4..687ef06 100644 --- a/client/src/pages/login.tsx +++ b/client/src/pages/login.tsx @@ -1,13 +1,17 @@ import { RoundButton } from '@/components/Buttons'; import { TextInput } from '@/components/Field'; -import { useHeader, useVh } from '@/hooks'; -import useAuth from '@/hooks/useAuth'; +import { useAuth, useHeader, useInput, useVh } from '@/hooks'; import { COLORS } from '@/styles/colors'; import { flex } from '@/styles/tokens'; import { TYPO } from '@/styles/typo'; import styled from '@emotion/styled'; import { useLayoutEffect } from 'react'; +type FormData = { + id: string; + password: string; +}; + /** * 로그인 페이지 */ @@ -15,6 +19,7 @@ const Login = () => { const { setHeader } = useHeader(); const { fullPageStyle } = useVh(); const { handleLogin } = useAuth(); + const { values, handleChange } = useInput({ id: '', password: '' }); useLayoutEffect(() => { setHeader('로그인'); @@ -25,15 +30,30 @@ const Login = () => { 학번 - + 비밀번호 - + - + handleLogin(values.id, values.password)} + /> 비밀번호를 재설정하고 싶어요. diff --git a/client/src/utils/lib/infoHandler.ts b/client/src/utils/lib/infoHandler.ts new file mode 100644 index 0000000..ae62306 --- /dev/null +++ b/client/src/utils/lib/infoHandler.ts @@ -0,0 +1,39 @@ +export type StudentInfo = { + name: string; + sId: string; + loginId: string; + password: string; +}; + +/** + * 정보 가져오기 + */ +export const getUserInfo = (): StudentInfo | null => { + const data = localStorage.getItem('USER_INFO'); + return data ? JSON.parse(data) : null; +}; + +/** + * 정보 업데이트 + */ +export const updateUserInfo = ( + name: string, + sId: string, + loginId: string, + password: string, +) => { + const data = { + name, + sId, + loginId, + password, + }; + localStorage.setItem('USER_INFO', JSON.stringify(data)); +}; + +/** + * 정보 삭제 (로그아웃) + */ +export const removeUserInfo = () => { + localStorage.removeItem('USER_INFO'); +};