diff --git a/src/pages/common/register/api/hooks/useRegister.ts b/src/pages/common/register/api/hooks/useRegister.ts new file mode 100644 index 00000000..f5e201e8 --- /dev/null +++ b/src/pages/common/register/api/hooks/useRegister.ts @@ -0,0 +1,47 @@ +import { useNavigate } from 'react-router-dom'; + +import { AxiosError } from 'axios'; + +import { RouterPath } from '@/app/routes/path'; +import { + SignupApiResponse, + registerUser, +} from '@/shared/api/auth/user-register'; +import { authLocalStorage } from '@/shared/utils/storage'; +import { useMutation } from '@tanstack/react-query'; + +const useRegister = () => { + const navigate = useNavigate(); + + const handleSuccess = (data: SignupApiResponse) => { + if ('status' in data && data.status === 207) { + alert(data.detail); + } else { + console.log(data); + if ('accessToken' in data) { + authLocalStorage.set(data.accessToken); + authLocalStorage.set(data.refreshToken); + alert('회원가입이 완료되었습니다.'); + navigate(data.isSinitto === 'true' ? RouterPath.ROOT : RouterPath.ROOT); + } + } + }; + + const handleError = (error: AxiosError) => { + if (error.response && error.response.data) { + alert('회원가입 중 오류가 발생했습니다.'); + } else { + alert('회원가입 중 네트워크 오류가 발생했습니다.'); + } + }; + + const mutation = useMutation({ + mutationFn: registerUser, + onSuccess: handleSuccess, + onError: handleError, + }); + + return mutation; +}; + +export default useRegister; diff --git a/src/pages/common/register/index.tsx b/src/pages/common/register/index.tsx index 9677a74c..b3dce8dd 100644 --- a/src/pages/common/register/index.tsx +++ b/src/pages/common/register/index.tsx @@ -1,6 +1,7 @@ import { useState } from 'react'; import { useForm } from 'react-hook-form'; +import useRegister from './api/hooks/useRegister'; import { RegisterFields } from './components/register-fields'; import { RegisterType } from './components/register-type'; import { Tos } from './components/tos'; @@ -17,13 +18,26 @@ const RegisterPage = () => { formState: { errors }, } = useForm(); + // 회원가입 처리 + const mutation = useRegister(); + const handleUserType = (id: string) => { setUserType(id); }; const onSubmit = (data: FormValues) => { - // 회원가입 api - console.log(userType, data); + // request 에 맞게 데이터 병합 + const isSinitto = userType === 'sinitto'; + + const requestData = { + name: data.name, + phoneNumber: data.phoneNumber, + email: 'test1@example.com', // 임시 (카카오 로그인 후 넘겨받기) + isSinitto, + }; + console.log(requestData); + // 회원가입 API 호출 + mutation.mutate(requestData); }; return ( diff --git a/src/shared/api/auth/user-register.ts b/src/shared/api/auth/user-register.ts new file mode 100644 index 00000000..f628e925 --- /dev/null +++ b/src/shared/api/auth/user-register.ts @@ -0,0 +1,53 @@ +import { fetchInstance } from '../instance'; + +// request(요청) 타입 +export type SignupReguestParams = { + name: string; + phoneNumber: string; + email: string; + isSinitto: boolean; +}; + +// response(응답) 타입 - 성공 +export type SignupResponse = { + accessToken: string; + refreshToken: string; + isSinitto?: 'true' | 'false'; +}; + +// 에러(아직 정확히 에러코드 확인 x) or 예외 +export type SignupErrorResponse = { + status: number; + detail: string; +}; + +// 공통 타입 정의 (onSuccess 내부에서 분기) +export type SignupApiResponse = SignupResponse | SignupErrorResponse; + +export const registerUser = async ({ + name, + phoneNumber, + email, + isSinitto, +}: SignupReguestParams): Promise => { + try { + // 시니또 보호자에 따라 API 엔드포인트 구분 + const endpoint = isSinitto ? 'sinitto' : 'guard'; + + const response = await fetchInstance.post(`/api/members/${endpoint}`, { + name, + phoneNumber, + email, + isSinitto, + }); + if (response.status === 207) { + return { + status: response.status, + detail: response.data.detail, + } as SignupErrorResponse; // 207 (예외 - 중복 이메일) + } + return response.data; // 200 + } catch (err) { + throw new Error('회원가입 실패'); + } +}; diff --git a/src/shared/api/instance/index.ts b/src/shared/api/instance/index.ts index 439db8ec..dbe8c22c 100644 --- a/src/shared/api/instance/index.ts +++ b/src/shared/api/instance/index.ts @@ -17,8 +17,10 @@ const initInstance = (config: AxiosRequestConfig): AxiosInstance => { return instance; }; +export const BASE_URL = 'http://43.201.254.198:8080'; + export const fetchInstance = initInstance({ - baseURL: 'https://api.example.com', + baseURL: 'http://43.201.254.198:8080', }); export const queryClient = new QueryClient({ diff --git a/src/shared/utils/storage/index.ts b/src/shared/utils/storage/index.ts new file mode 100644 index 00000000..c562a0b8 --- /dev/null +++ b/src/shared/utils/storage/index.ts @@ -0,0 +1,24 @@ +type StorageKey = { + accessToken?: string; +}; + +const initStorage = (key: T, storage: Storage) => { + const storageKey = `${key}`; + + const get = (): StorageKey[T] => { + const value = storage.getItem(storageKey); + return value as StorageKey[T]; + }; + + const set = (value: StorageKey[T]) => { + if (value == undefined || value == null) { + return storage.removeItem(storageKey); + } + const stringifiedValue = JSON.stringify(value); + storage.setItem(storageKey, stringifiedValue); + }; + + return { get, set }; +}; + +export const authLocalStorage = initStorage('accessToken', localStorage);