From 07493a994329874f23448818b1740c0b56a0f7dc Mon Sep 17 00:00:00 2001 From: MOON Date: Wed, 17 Jul 2024 13:19:30 +0900 Subject: [PATCH 1/5] =?UTF-8?q?:sparkles:=20=EB=A1=9C=EA=B7=B8=EC=9D=B8=20?= =?UTF-8?q?=EC=9D=91=EB=8B=B5=20=EB=8D=B0=EC=9D=B4=ED=84=B0=20=EC=8A=A4?= =?UTF-8?q?=ED=82=A4=EB=A7=88=20=EC=A0=95=EC=9D=98?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/schema/auth.ts | 17 +++++++++++++++++ 1 file changed, 17 insertions(+) diff --git a/src/schema/auth.ts b/src/schema/auth.ts index 9fcd92dd..33466608 100644 --- a/src/schema/auth.ts +++ b/src/schema/auth.ts @@ -5,4 +5,21 @@ export const PostSigninRequest = z.object({ password: z.string().min(1, { message: '비밀번호는 필수 입력입니다.' }), }); +const User = z.object({ + id: z.number(), + email: z.string().email(), + nickname: z.string(), + teamId: z.string(), + updatedAt: z.coerce.date(), + createdAt: z.coerce.date(), + image: z.string(), +}); + +export const PostSigninResponse = z.object({ + accessToken: z.string(), + refreshToken: z.string(), + user: User, +}); + export type PostSigninRequestType = z.infer; +export type PostSigninResponseType = z.infer; From 10c64402a5f74e3c8574bfada468f06593dea4bd Mon Sep 17 00:00:00 2001 From: MOON Date: Wed, 17 Jul 2024 14:13:51 +0900 Subject: [PATCH 2/5] =?UTF-8?q?:sparkles:=20=EB=A1=9C=EA=B7=B8=EC=9D=B8=20?= =?UTF-8?q?api=20=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/apis/auth.ts | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) create mode 100644 src/apis/auth.ts diff --git a/src/apis/auth.ts b/src/apis/auth.ts new file mode 100644 index 00000000..60ba8f4d --- /dev/null +++ b/src/apis/auth.ts @@ -0,0 +1,30 @@ +import type { PostSigninRequestType, PostSigninResponseType } from '@/schema/auth'; +import { AxiosError } from 'axios'; +import httpClient from '.'; + +const postSignin = async (request: PostSigninRequestType): Promise => { + try { + const response = await httpClient.post('/auth/signIn', request); + return response.data; + } catch (error) { + if (error instanceof AxiosError) { + // Axios 에러인 경우 + const axiosError = error as AxiosError; + if (axiosError.response) { + // 서버에서 응답이 온 경우 (예: 4xx, 5xx) + throw new Error('로그인 요청 처리 중 문제가 발생했습니다.'); + } else if (axiosError.request) { + // 요청을 보냈지만 응답을 받지 못한 경우 + throw new Error('서버 응답을 받지 못했습니다. 잠시 후 다시 시도해 주세요.'); + } else { + // 요청을 설정하는 과정에서 문제가 발생한 경우 + throw new Error('로그인 요청을 처리하는 동안 문제가 발생했습니다.'); + } + } else { + // Axios 에러가 아닌 경우 (네트워크 문제 등) + throw new Error('알 수 없는 오류가 발생했습니다. 잠시 후 다시 시도해 주세요.'); + } + } +}; + +export default postSignin; From 539238401b4540d7ff8cd6adb3f388aee46bc91d Mon Sep 17 00:00:00 2001 From: MOON Date: Wed, 17 Jul 2024 14:16:15 +0900 Subject: [PATCH 3/5] =?UTF-8?q?:sparkles:=20=EC=9A=94=EC=B2=AD=EA=B3=BC=20?= =?UTF-8?q?=EC=9D=91=EB=8B=B5=EC=97=90=20=EA=B4=80=ED=95=9C=20=EC=9D=B8?= =?UTF-8?q?=ED=84=B0=EC=85=89=ED=84=B0=20=EC=B6=94=EA=B0=80?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/apis/index.ts | 39 +++++++++++++++++++++++++++++++++++++++ 1 file changed, 39 insertions(+) diff --git a/src/apis/index.ts b/src/apis/index.ts index 29949fc2..a1b6aaec 100644 --- a/src/apis/index.ts +++ b/src/apis/index.ts @@ -8,3 +8,42 @@ const httpClient = axios.create({ }); export default httpClient; + +// NOTE: eslint-disable no-param-reassign 미해결로 인한 설정 +httpClient.interceptors.request.use((config) => { + const accessToken = localStorage.getItem('accessToken'); + /* eslint-disable no-param-reassign */ + if (accessToken) config.headers.Authorization = `Bearer ${accessToken}`; + /* eslint-enable no-param-reassign */ + return config; +}); + +httpClient.interceptors.response.use( + (response) => response, + + (error) => { + if (error.response && error.response.status === 401) { + const refreshToken = localStorage.getItem('refreshToken'); + + if (!refreshToken) { + window.location.href = '/auth/SignIn'; + } else { + httpClient + .post('/auth/refresh-token', null, { + headers: { Authorization: `Bearer ${refreshToken}` }, + }) + .then((response) => { + const { accessToken } = response.data; + const { refreshToken: newRefreshToken } = response.data; + localStorage.setItem('accessToken', accessToken); + localStorage.setItem('refreshToken', newRefreshToken); + }) + .catch(() => { + window.location.href = '/auth/SignIn'; + }); + } + } else { + throw new Error(error.response.status); + } + }, +); From 22106ac3634810aefe035a90fd91b457d4256907 Mon Sep 17 00:00:00 2001 From: MOON Date: Wed, 17 Jul 2024 14:56:35 +0900 Subject: [PATCH 4/5] =?UTF-8?q?:sparkles:=20useSignin=20mutation=20hook=20?= =?UTF-8?q?=EC=83=9D=EC=84=B1?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/hooks/userQueryHooks.ts | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/src/hooks/userQueryHooks.ts b/src/hooks/userQueryHooks.ts index 7c28fe75..005fcf8c 100644 --- a/src/hooks/userQueryHooks.ts +++ b/src/hooks/userQueryHooks.ts @@ -1,8 +1,10 @@ +import postSignin from '@/apis/auth'; import quries from '@/apis/queries'; import { updateMe } from '@/apis/user'; import { GetUserReponseType, GetUserRequestType, PatchMeRequestType } from '@/schema/user'; import { MutationOptions } from '@/types/query'; import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'; +import { useRouter } from 'next/router'; export const useMeQuery = () => useQuery(quries.user.getMe()); @@ -21,3 +23,21 @@ export const useUpdateMe = (options: MutationOptions) => { }, }); }; + +export const useSignin = () => { + const router = useRouter(); + + return useMutation({ + mutationFn: postSignin, + onSuccess: (data) => { + localStorage.setItem('accessToken', data.accessToken); + localStorage.setItem('refreshToken', data.refreshToken); + router.push('/'); + }, + onError: (error) => { + // NOTE: 임시 테스트용 콘솔, 토스트 추가 예정 + /* eslint-disable no-console */ + console.error(error); + }, + }); +}; From e4bebb9be8b96a3f51f0b841e482211fc2f8ff4d Mon Sep 17 00:00:00 2001 From: MOON Date: Wed, 17 Jul 2024 14:57:11 +0900 Subject: [PATCH 5/5] =?UTF-8?q?:zap:=20useSignin=20hook=20=EB=A1=9C?= =?UTF-8?q?=EA=B7=B8=EC=9D=B8=20=ED=8F=BC=EC=97=90=20=EC=A0=81=EC=9A=A9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/pages/auth/SignIn.tsx | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/pages/auth/SignIn.tsx b/src/pages/auth/SignIn.tsx index 49a869f3..d19775e1 100644 --- a/src/pages/auth/SignIn.tsx +++ b/src/pages/auth/SignIn.tsx @@ -7,8 +7,10 @@ import { useForm } from 'react-hook-form'; import { zodResolver } from '@hookform/resolvers/zod'; import { Form, FormControl, FormField, FormItem, FormMessage } from '@/components/ui/form'; import { PostSigninRequest, PostSigninRequestType } from '@/schema/auth'; +import { useSignin } from '@/hooks/userQueryHooks'; export default function SignIn() { + const mutationSignin = useSignin(); // 폼 정의 const form = useForm({ resolver: zodResolver(PostSigninRequest), @@ -20,9 +22,7 @@ export default function SignIn() { }); function onSubmit(values: PostSigninRequestType) { - // NOTE : 테스트를 위해서 콘솔 넣음 - /* eslint-disable no-console */ - console.log(values); + mutationSignin.mutate(values); } // TODO: 나중에 컴포넌트 분리하기