Skip to content

Commit

Permalink
[정성현] sprint12 (#138)
Browse files Browse the repository at this point in the history
* refactor: 페이지 폴더 구조 변경

- 페이지명/index.tsx 방식으로 변경

* chore: 라이브러리 설치

- Axios, Tanstack Query, React Hook Form 설치

* refactor: API 리팩토링

- Fetch API에서 Axios 라이브러리로 전환
- API 상수와 타입을 분리

* feat: 로그인 상태 전역상태화

- 컨텍스트를 활용하여 로그인 상태 전역상태화

* feat: 중고마켓 베스트 상품 구현

- products API 추가
- 탠스택 쿼리의 useQuery 활용
  • Loading branch information
jsh1147 authored Dec 9, 2024
1 parent 2cc3287 commit b84553b
Show file tree
Hide file tree
Showing 25 changed files with 637 additions and 53 deletions.
1 change: 1 addition & 0 deletions next.config.js
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ const nextConfig = {
hostname: "sprint-fe-project.s3.ap-northeast-2.amazonaws.com",
pathname: "/Sprint_Mission/user/**",
},
{ protocol: "https", hostname: "image.hanatour.com" },
],
},
};
Expand Down
162 changes: 147 additions & 15 deletions package-lock.json

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

9 changes: 6 additions & 3 deletions package.json
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,19 @@
"lint": "next lint"
},
"dependencies": {
"@tanstack/react-query": "^5.62.3",
"axios": "^1.7.9",
"next": "13.5.6",
"react": "^18",
"react-dom": "^18",
"next": "13.5.6"
"react-hook-form": "^7.54.0"
},
"devDependencies": {
"typescript": "^5",
"@types/node": "^20",
"@types/react": "^18",
"@types/react-dom": "^18",
"eslint": "^8",
"eslint-config-next": "13.5.6"
"eslint-config-next": "13.5.6",
"typescript": "^5"
}
}
36 changes: 36 additions & 0 deletions src/apis/auth.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
import { instance } from "./instance";
import { PATH } from "@/constants/api";
import {
PostSignUpParams,
PostSignUpRes,
PostLogInParams,
PostLogInRes,
PostRefreshParams,
PostRefreshRes,
} from "@/types/api";

export const postSignUp = async ({
email,
nickname,
password,
passwordConfirmation,
}: PostSignUpParams) => {
const bodyObj = { email, nickname, password, passwordConfirmation };

const response = await instance.post<PostSignUpRes>(PATH.SIGNUP, bodyObj);
return response.data;
};

export const postLogIn = async ({ email, password }: PostLogInParams) => {
const bodyObj = { email, password };

const response = await instance.post<PostLogInRes>(PATH.LOGIN, bodyObj);
return response.data;
};

export const postRefresh = async ({ refreshToken }: PostRefreshParams) => {
const bodyObj = { refreshToken };

const response = await instance.post<PostRefreshRes>(PATH.REFRESH, bodyObj);
return response.data;
};
38 changes: 38 additions & 0 deletions src/apis/instance.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
import axios, { AxiosError } from "axios";
import { postRefresh } from "./auth";
import { BASE_URL } from "@/constants/api";

export const instance = axios.create({
baseURL: BASE_URL,
headers: { "Content-Type": "application/json" },
});

instance.interceptors.request.use(async (config) => {
if (config.url === "auth/refresh-token") return config;

try {
const refresh = localStorage.getItem("refreshToken");
if (!refresh) throw new AxiosError("저장된 유저 정보가 없습니다.", "401");

const { accessToken } = await postRefresh({ refreshToken: refresh });
localStorage.setItem("accessToken", accessToken);
} catch {
localStorage.removeItem("accessToken");
localStorage.removeItem("refreshToken");
}

const access = localStorage.getItem("accessToken");
if (access) config.headers["Authorization"] = `Bearer ${access}`;
return config;
});

instance.interceptors.response.use(
(response) => response,
(error: AxiosError<{ message: string }>) => {
const res = error.response;
if (res)
console.log(`[${error.status}:${res.config.url}] ${res.data.message}`);

return Promise.reject(error);
}
);
17 changes: 17 additions & 0 deletions src/apis/product.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
import { instance } from "./instance";
import { PATH } from "@/constants/api";
import { GetProductsParams, GetProductsRes } from "@/types/api";

export const getProducts = async ({
page = 1,
pageSize = 10,
orderBy = "recent",
keyword,
}: GetProductsParams) => {
const paramObj = { page, pageSize, orderBy, ...(keyword && { keyword }) };

const response = await instance.get<GetProductsRes>(PATH.PRODUCTS, {
params: paramObj,
});
return response.data;
};
Loading

0 comments on commit b84553b

Please sign in to comment.