From 4dbb228d0c583c044c9ed7429650a5c7d7292309 Mon Sep 17 00:00:00 2001 From: HiImConan Date: Wed, 29 Nov 2023 02:16:41 +0900 Subject: [PATCH 1/2] =?UTF-8?q?feat:=20=EB=A1=9C=EA=B7=B8=EC=9D=B8=20?= =?UTF-8?q?=EB=AE=A4=ED=85=8C=EC=9D=B4=EC=85=98=20=EC=BF=BC=EB=A6=AC=20?= =?UTF-8?q?=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/queries/useLogin/query.ts | 31 +++++++++++++++++++++++++++++++ 1 file changed, 31 insertions(+) create mode 100644 src/queries/useLogin/query.ts diff --git a/src/queries/useLogin/query.ts b/src/queries/useLogin/query.ts new file mode 100644 index 0000000..81bd4b5 --- /dev/null +++ b/src/queries/useLogin/query.ts @@ -0,0 +1,31 @@ +import { useMutation, useQueryClient } from '@tanstack/react-query'; +import { useRouter } from 'next/router'; + +import { adminInstance } from '@/api'; +import { postLogin } from '@/api/auth'; +import { AuthPayload } from '@/types/auth'; + +export default function usePostLoginMutation({ email, password }: AuthPayload) { + const queryClient = useQueryClient(); + const router = useRouter(); + + return useMutation({ + mutationFn: () => postLogin({ email, password }), + onSuccess: ({ access }) => { + localStorage.setItem('token', access); + + adminInstance.interceptors.request.use(config => { + config.headers.Authorization = `Bearer ${access}`; + + return config; + }); + + queryClient.setQueryData(['login'], access); + + router.push('/admin/league'); + }, + // onError: () => { + // setIsLoginFailed(true); + // }, + }); +} From 5cab525997a474e0a51358baddef286551dd0c9c Mon Sep 17 00:00:00 2001 From: HiImConan Date: Wed, 29 Nov 2023 03:45:06 +0900 Subject: [PATCH 2/2] =?UTF-8?q?feat:=20=EB=A1=9C=EA=B7=B8=EC=9D=B8=20?= =?UTF-8?q?=EB=A6=AC=ED=8C=A9=ED=86=A0=EB=A7=81,=20=EC=95=84=EC=9D=B4?= =?UTF-8?q?=EC=BD=98=20=EB=88=84=EB=9D=BD=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/app/login/page.tsx | 85 ++++++++++++++++-------- src/components/common/Icon/iconMap.ts | 2 + src/queries/admin/useLeagueList/query.ts | 1 + src/queries/useLogin/query.ts | 7 +- 4 files changed, 64 insertions(+), 31 deletions(-) diff --git a/src/app/login/page.tsx b/src/app/login/page.tsx index 7c7b113..bbd86aa 100644 --- a/src/app/login/page.tsx +++ b/src/app/login/page.tsx @@ -1,19 +1,32 @@ 'use client'; -import { useRouter } from 'next/navigation'; +import { ChangeEvent, useState } from 'react'; -import { postLogin } from '@/api/auth'; +import Button from '@/components/common/Button'; +import Input from '@/components/common/Input/Input'; +import useValidate from '@/hooks/useValidate'; +import usePostLoginMutation from '@/queries/useLogin/query'; +import { AuthPayload } from '@/types/auth'; export default function Login() { - const router = useRouter(); + const [loginData, setLoginData] = useState({} as AuthPayload); - const login = async (email: string, password: string) => { - const data = await postLogin({ - email: email, - password: password, - }); + const { mutate } = usePostLoginMutation(); - return data.access; + const { isError: isEmailEmpty } = useValidate( + loginData.email, + emailValue => !emailValue, + ); + const { isError: isPasswordEmpty } = useValidate( + loginData.password, + pwValue => !pwValue, + ); + const isAnyInvaild = isEmailEmpty || isPasswordEmpty; + + const handleInput = (e: ChangeEvent) => { + const { name, value } = e.target; + + setLoginData(prev => ({ ...prev, [name]: value })); }; const loginSubmitHandler = async ( @@ -21,32 +34,50 @@ export default function Login() { ) => { event.preventDefault(); - const formData = new FormData(event.currentTarget); - const loginRes = await login( - formData.get('email') as string, - formData.get('password') as string, - ); - if (!loginRes) return; - - localStorage.setItem('token', loginRes); - router.push('/'); + mutate(loginData); }; return ( -
+
+
관리자 로그인
-
); diff --git a/src/components/common/Icon/iconMap.ts b/src/components/common/Icon/iconMap.ts index 9ad7269..400b6fc 100644 --- a/src/components/common/Icon/iconMap.ts +++ b/src/components/common/Icon/iconMap.ts @@ -2,6 +2,7 @@ import { BackgroundLogo } from './svg/BackgroundLogo'; import { Calendar } from './svg/Calendar'; import { CaretDown } from './svg/CaretDown'; import { CaretUp } from './svg/CaretUp'; +import { CheckCircled } from './svg/CheckCircled'; import { Clip } from './svg/Clip'; import { Cross } from './svg/Cross'; import { HamburgerMenu } from './svg/HamburgerMenu'; @@ -21,6 +22,7 @@ export const iconMap = { caretDown: CaretDown, caretUp: CaretUp, clip: Clip, + checkCircled: CheckCircled, cross: Cross, hamburgerMenu: HamburgerMenu, hcc: Hcc, diff --git a/src/queries/admin/useLeagueList/query.ts b/src/queries/admin/useLeagueList/query.ts index a50f0bf..5403ccc 100644 --- a/src/queries/admin/useLeagueList/query.ts +++ b/src/queries/admin/useLeagueList/query.ts @@ -29,6 +29,7 @@ export function useDeleteLeagueMutation() { const queryClient = useQueryClient(); return useMutation({ + mutationKey: ['delete-league'], mutationFn: deleteLeagueByIdWithAuth, onSuccess: () => { queryClient.invalidateQueries({ diff --git a/src/queries/useLogin/query.ts b/src/queries/useLogin/query.ts index 81bd4b5..42cfc4f 100644 --- a/src/queries/useLogin/query.ts +++ b/src/queries/useLogin/query.ts @@ -1,16 +1,15 @@ import { useMutation, useQueryClient } from '@tanstack/react-query'; -import { useRouter } from 'next/router'; +import { useRouter } from 'next/navigation'; import { adminInstance } from '@/api'; import { postLogin } from '@/api/auth'; -import { AuthPayload } from '@/types/auth'; -export default function usePostLoginMutation({ email, password }: AuthPayload) { +export default function usePostLoginMutation() { const queryClient = useQueryClient(); const router = useRouter(); return useMutation({ - mutationFn: () => postLogin({ email, password }), + mutationFn: postLogin, onSuccess: ({ access }) => { localStorage.setItem('token', access);