diff --git a/src/api/auth/auth.delete.api.ts b/src/api/auth/auth.delete.api.ts new file mode 100644 index 0000000..3303f44 --- /dev/null +++ b/src/api/auth/auth.delete.api.ts @@ -0,0 +1 @@ +/* 회원탈퇴 */ diff --git a/src/api/auth/auth.get.api.ts b/src/api/auth/auth.get.api.ts new file mode 100644 index 0000000..6f25f8d --- /dev/null +++ b/src/api/auth/auth.get.api.ts @@ -0,0 +1,10 @@ +// import { ICommon } from '../types/common'; +import { getRequest } from '../request'; +import { IUpdateProfile } from '../types/auth'; + +/* 회원 상세정보 */ + +export const userinfo = async () => { + const response = await getRequest('members'); + return response; +}; diff --git a/src/api/auth/auth.patch.api.ts b/src/api/auth/auth.patch.api.ts new file mode 100644 index 0000000..c345b34 --- /dev/null +++ b/src/api/auth/auth.patch.api.ts @@ -0,0 +1 @@ +/* 비밀번호 재설정 */ diff --git a/src/api/auth/auth.post.api.ts b/src/api/auth/auth.post.api.ts new file mode 100644 index 0000000..17be0b4 --- /dev/null +++ b/src/api/auth/auth.post.api.ts @@ -0,0 +1,99 @@ +// import { ICommon } from '../types/common'; +import { postRequest } from '../request'; +import { + ISignIn, + ISignUp, + UserInfoType, + IEmail, + IEmailAuth, + IPhoneNumber, + IPhoneAuth +} from '../types/auth'; + +/* 회원가입 */ + +export const signup = async ({ + memberEmail, + memberPassword, + memberName, + memberGender, + memberJob, + memberPhone, + memberBirthDate, + memberSmsAgree +}: ISignUp) => { + const response = await postRequest('members', { + memberEmail, + memberPassword, + memberName, + memberGender, + memberJob, + memberPhone, + memberBirthDate, + memberSmsAgree + }); + return response; +}; + +/* 로그인 */ + +export const signin = async ({ memberEmail, memberPassword }: ISignIn) => { + const response = await postRequest('login', { + memberEmail, + memberPassword + }); + + return response; +}; + +/* 이메일 인증 요청 */ + +export const emailauthrequest = async ({ emailAddress }: IEmail) => { + const response = await postRequest('auth/email', { + emailAddress + }); + + return response; +}; + +/* 이메일 코드 검증 */ + +export const emailauthverify = async ({ emailAddress, code }: IEmailAuth) => { + const response = await postRequest('auth/email/verify', { + emailAddress, + code + }); + + return response; +}; + +/* 휴대전화 번호 인증 요청*/ + +export const phoneauthrequest = async ({ phoneNumber }: IPhoneNumber) => { + const response = await postRequest('/auth/phone', { + phoneNumber + }); + + return response; +}; + +/* 휴대전화 번호 코드 검증*/ + +export const phoneauthverify = async ({ phoneNumber, code }: IPhoneAuth) => { + const response = await postRequest('/auth/phone/verify', { + phoneNumber, + code + }); + + return response; +}; + +/* 로그아웃*/ + +export const logout = async () => { + const response = await postRequest('/logout'); + + return response; +}; + +/* 토큰 리프레쉬*/ diff --git a/src/api/instance.ts b/src/api/instance.ts new file mode 100644 index 0000000..5166884 --- /dev/null +++ b/src/api/instance.ts @@ -0,0 +1,84 @@ +import { toast } from 'react-toastify'; +import axios, { + Axios, + InternalAxiosRequestConfig, + AxiosError, + AxiosResponse +} from 'axios'; + +import { getCookie } from '@utils/cookies'; +import logOnDev from '@utils/logOnDev'; + +export const instance: Axios = axios.create({ + baseURL: process.env.NEXT_PUBLIC_BASE_URL, + withCredentials: true, + headers: { + 'Content-Type': 'application/json', + Accept: '*/*' + }, + timeout: 3000 +}); + +instance.interceptors.request.use( + (config: InternalAxiosRequestConfig): InternalAxiosRequestConfig => { + const token = getCookie('token') as string; + const id = getCookie('id') as string; + if (config && config.headers) { + if (token) { + config.headers.Authorization = token; + config.headers.id = id; + } + } + if (process.env.NODE_ENV === 'development') { + const { method, url } = config; + logOnDev(`🚀 [API] ${method?.toUpperCase()} ${url} | Request`); + } + return config; + }, + (error: AxiosError | Error): Promise => { + return Promise.reject(error); + } +); + +instance.interceptors.response.use( + (response: AxiosResponse): AxiosResponse => { + return response; + }, + (error: AxiosError | Error): Promise => { + if (process.env.NODE_ENV === 'development') { + if (axios.isAxiosError(error)) { + const { message } = error; + const { method, url } = error.config as InternalAxiosRequestConfig; + const { status, statusText } = error.response as AxiosResponse; + logOnDev( + `🚨 [API] ${method?.toUpperCase()} ${url} | Error ${status} ${statusText} | ${message}` + ); + switch (status) { + case 401: { + toast.error('로그인이 필요합니다'); + break; + } + case 403: { + toast.error('잘못된 권한입니다'); + break; + } + case 404: { + toast.error('잘못된 요청입니다'); + break; + } + case 500: { + toast.error('서버 에러 발생'); + break; + } + default: { + toast.error('알 수 없는 오류 발생'); + break; + } + } + } else { + logOnDev(`🚨 [API] | Error ${error.message}`); + } + } + return Promise.reject(error); + } +); diff --git a/src/api/request.ts b/src/api/request.ts new file mode 100644 index 0000000..f4c790c --- /dev/null +++ b/src/api/request.ts @@ -0,0 +1,60 @@ +/* eslint-disable @typescript-eslint/no-explicit-any */ +import { AxiosRequestConfig, InternalAxiosRequestConfig } from 'axios'; + +import { instance } from './instance'; + +/* get 요청 */ +export const getRequest = async ( + url: string, + config?: AxiosRequestConfig +): Promise => { + const response = await instance.get(url, config as InternalAxiosRequestConfig); + return response.data; +}; + +/* post 요청 */ +export const postRequest = async ( + url: string, + data?: D, + config?: AxiosRequestConfig +): Promise => { + const response = await instance.post( + url, + data, + config as InternalAxiosRequestConfig + ); + return response.data; +}; + +/* delete 요청 */ +export const deleteRequest = async ( + url: string, + config?: AxiosRequestConfig +): Promise => { + const response = await instance.delete(url, config as InternalAxiosRequestConfig); + return response.data; +}; + +/* put 요청 */ +export const putRequest = async ( + url: string, + data: D, + config?: AxiosRequestConfig +): Promise => { + const response = await instance.put(url, data, config as InternalAxiosRequestConfig); + return response.data; +}; + +/* patch 요청 */ +export const patchRequest = async ( + url: string, + data: D, + config?: AxiosRequestConfig +): Promise => { + const response = await instance.patch( + url, + data, + config as InternalAxiosRequestConfig + ); + return response.data; +}; diff --git a/src/api/types/auth.ts b/src/api/types/auth.ts new file mode 100644 index 0000000..9834860 --- /dev/null +++ b/src/api/types/auth.ts @@ -0,0 +1,57 @@ +import { ICommon } from './common'; + +export interface ISignIn { + memberEmail: string; + memberPassword: string; +} + +export interface ISignUp extends ISignIn { + memberName: string; + memberGender: string; + memberJob: string; + memberPhone: string; + memberBirthDate: string; + memberSmsAgree: boolean; +} + +export interface IUpdateProfile { + memberEmail: string; + memberName: string; + memberJob: string; + memberPhone: string; + memberBirthDate: string; +} + +export interface IPhoneNumber { + phoneNumber: string; +} + +export interface IPhoneAuth extends IPhoneNumber { + code: number; +} + +export interface IUserInfo { + memberEmail: string; + memberName: string; + memberJob: string; + memberPhone: string; + memberBirthDate: string; +} + +export interface IWithdraw { + memberPassword: string; +} + +export interface IEmail { + emailAddress: string; +} +export interface IEmailAuth extends IEmail { + code: number; +} + +export interface ITokenRefresh { + // 아직 타입 안들어옴 +} +export type FindPassword = Pick; +export type ChangePassword = Pick; +export type UserInfoType = ICommon; diff --git a/src/api/types/common.ts b/src/api/types/common.ts new file mode 100644 index 0000000..37788ce --- /dev/null +++ b/src/api/types/common.ts @@ -0,0 +1,6 @@ +export interface ICommon { + status: number; + code: string; + message: string; + value: T; +} diff --git a/src/types/cookies.type.ts b/src/types/cookies.type.ts new file mode 100644 index 0000000..3f2ffb0 --- /dev/null +++ b/src/types/cookies.type.ts @@ -0,0 +1,19 @@ +export interface CookieGetOptions { + doNotParse?: boolean; + doNotUpdate?: boolean; +} +export interface CookieSetOptions { + path?: string; + expires?: Date; + maxAge?: number; + domain?: string; + secure?: boolean; + httpOnly?: boolean; + sameSite?: boolean | 'none' | 'lax' | 'strict'; +} +export interface CookieChangeOptions { + name: string; + // eslint-disable-next-line @typescript-eslint/no-explicit-any + value?: any; + options?: CookieSetOptions; +}