Skip to content

Commit 194715a

Browse files
committed
Merge branch 'dev' of https://github.com/CodeitPart3/thejulge into COMPONENT-29-HONG
2 parents c2992cd + b6ba6fb commit 194715a

18 files changed

+561
-0
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ node_modules
1111
dist
1212
dist-ssr
1313
*.local
14+
.env
1415

1516
# Editor directories and files
1617
.vscode/*

src/apis/client/interceptors.tsx

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
import type { InternalAxiosRequestConfig } from "axios";
2+
3+
export const requestInterceptor = (
4+
config: InternalAxiosRequestConfig,
5+
): InternalAxiosRequestConfig => {
6+
const token: string | null = localStorage.getItem("token");
7+
8+
if (token) {
9+
config.headers.Authorization = `Bearer ${token}`;
10+
}
11+
12+
return config;
13+
};

src/apis/client/requestor.tsx

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
import axios, { AxiosError, AxiosInstance } from "axios";
2+
3+
import { requestInterceptor } from "./interceptors";
4+
5+
const requestor: AxiosInstance = axios.create({
6+
baseURL: (import.meta.env.VITE_API_ENDPOINT as string).trim(),
7+
timeout: 60000,
8+
headers: {
9+
"Content-Type": "application/json",
10+
Accept: "application/json",
11+
},
12+
});
13+
14+
requestor.interceptors.request.use(requestInterceptor, (error: AxiosError) => {
15+
return Promise.reject(error);
16+
});
17+
18+
export default requestor;

src/apis/index.ts

Whitespace-only changes.

src/apis/services/alertService.tsx

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
import type { AxiosResponse } from "axios";
2+
import { AlertListResponse, AlertReadListResponse } from "src/types";
3+
4+
import requestor from "../client/requestor";
5+
6+
/* 유저의 알림 목록 조회 */
7+
export const getAlerts = (
8+
userId: string,
9+
offset: number = 0,
10+
limit?: number,
11+
): Promise<AxiosResponse<AlertListResponse>> => {
12+
return requestor.get(`/users/${userId}/alerts`, {
13+
params: { offset, limit },
14+
});
15+
};
16+
17+
/* 알림 읽음 처리 */
18+
export const putAlert = (
19+
userId: string,
20+
alertId: string,
21+
): Promise<AxiosResponse<AlertReadListResponse>> => {
22+
return requestor.put(`/users/${userId}/alerts/${alertId}`);
23+
};
Lines changed: 53 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,53 @@
1+
import type { AxiosResponse } from "axios";
2+
import {
3+
ApplicationListResponse,
4+
ApplicationResponse,
5+
ApplicationStatus,
6+
UserApplicationListResponse,
7+
} from "src/types";
8+
9+
import requestor from "../client/requestor";
10+
11+
/* 가게의 특정 공고의 지원 목록 조회 */
12+
export const getShopApplications = (
13+
shopId: string,
14+
noticeId: string,
15+
offset?: number,
16+
limit?: number,
17+
): Promise<AxiosResponse<ApplicationListResponse>> => {
18+
return requestor.get(`/shops/${shopId}/notices/${noticeId}/applications`, {
19+
params: { offset, limit },
20+
});
21+
};
22+
23+
/* 가게의 특정 공고 지원 등록 */
24+
export const postApplication = (
25+
shopId: string,
26+
noticeId: string,
27+
): Promise<AxiosResponse<ApplicationResponse>> => {
28+
return requestor.post(`/shops/${shopId}/notices/${noticeId}/applications`);
29+
};
30+
31+
/* 가게의 특정 공고 지원 승인, 거절 또는 취소소 */
32+
export const putApplication = (
33+
shopId: string,
34+
noticeId: string,
35+
applicationId: string,
36+
status: Exclude<ApplicationStatus, "pending">,
37+
): Promise<AxiosResponse<ApplicationResponse>> => {
38+
return requestor.put(
39+
`/shops/${shopId}/notices/${noticeId}/applications/${applicationId}`,
40+
{ status },
41+
);
42+
};
43+
44+
/* 유저의 지원 목록 조회 */
45+
export const getUserApplications = (
46+
userId: string,
47+
offset?: number,
48+
limit?: number,
49+
): Promise<AxiosResponse<UserApplicationListResponse>> => {
50+
return requestor.get(`/users/${userId}/applications`, {
51+
params: { offset, limit },
52+
});
53+
};
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
import type { AxiosResponse } from "axios";
2+
import type { ApiWithHref, UserItem } from "src/types";
3+
import { ApiWrapper } from "src/types";
4+
5+
import requestor from "../client/requestor";
6+
7+
interface LoginItem {
8+
token: string;
9+
user: ApiWithHref<UserItem>;
10+
}
11+
12+
export type LoginRequest = { email: string; password: string };
13+
export type LoginResponse = ApiWrapper<LoginItem>;
14+
15+
/* 로그인 */
16+
export const postAuthentication = async (
17+
payload: LoginRequest,
18+
): Promise<AxiosResponse<LoginResponse>> => {
19+
const res = await requestor.post<LoginResponse>("/token", payload);
20+
21+
const token = res.data.item.token;
22+
const user = res.data.item.user.item;
23+
24+
localStorage.setItem("token", token);
25+
localStorage.setItem("user", JSON.stringify(user));
26+
27+
return res;
28+
};
29+
30+
/* 로그아웃 */
31+
export const logout = () => {
32+
localStorage.removeItem("token");
33+
localStorage.removeItem("user");
34+
};
35+
36+
/* 토큰 반환 */
37+
export const getToken = () => {
38+
return localStorage.getItem("token");
39+
};
40+
41+
/* 인증 여부 확인 */
42+
export const isAuthenticated = () => {
43+
return Boolean(getToken());
44+
};

src/apis/services/imageService.tsx

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
import axios, { AxiosResponse } from "axios";
2+
import { ApiWrapper } from "src/types";
3+
4+
import requestor from "../client/requestor";
5+
6+
interface PresignedItem {
7+
url: string;
8+
}
9+
type PresignedResponse = ApiWrapper<PresignedItem>;
10+
11+
/* Presigned URL 생성 */
12+
export const postImage = async (name: string): Promise<string> => {
13+
const res: AxiosResponse<PresignedResponse> = await requestor.post(
14+
"/images",
15+
{ name },
16+
);
17+
return res.data.item.url;
18+
};
19+
20+
/* S3로 이미지 업로드 */
21+
export const putImage = async (
22+
presignedURL: string,
23+
file: File | Blob,
24+
): Promise<AxiosResponse<void>> => {
25+
return axios.put(presignedURL, file, {
26+
headers: { "Content-Type": file.type || "application/octet-stream" },
27+
});
28+
};
29+
30+
/* Presigned URL 조회 */
31+
export const getPublicURL = (presignedURL: string) => {
32+
return presignedURL.split("?")[0];
33+
};
34+
35+
/* 이미지 조회 */
36+
export const getImage = (publicURL: string): Promise<AxiosResponse<Blob>> => {
37+
return axios.get(publicURL, { responseType: "blob" });
38+
};
Lines changed: 52 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,52 @@
1+
import type { AxiosResponse } from "axios";
2+
import {
3+
NoticeResponse,
4+
NoticePayload,
5+
GetNoticesParams,
6+
NoticeListResponseWithoutUserApplication,
7+
} from "src/types";
8+
9+
import requestor from "../client/requestor";
10+
11+
/* 공고 조회 */
12+
export const getNotices = (
13+
params?: GetNoticesParams,
14+
): Promise<AxiosResponse<NoticeListResponseWithoutUserApplication>> => {
15+
return requestor.get("/notices", { params });
16+
};
17+
18+
/* 가게의 공고 목록 조회 */
19+
export const getShopNotices = (
20+
shopId: string,
21+
offset?: number,
22+
limit?: number,
23+
): Promise<AxiosResponse<NoticeListResponseWithoutUserApplication>> => {
24+
return requestor.get(`/shops/${shopId}/notices`, {
25+
params: { offset, limit },
26+
});
27+
};
28+
29+
/* 가게 공고 등록 */
30+
export const postNotice = (
31+
shopId: string,
32+
payload: NoticePayload,
33+
): Promise<AxiosResponse<NoticeResponse>> => {
34+
return requestor.post(`/shops/${shopId}/notices`, payload);
35+
};
36+
37+
/* 가게의 특정 공고 조회 */
38+
export const getNotice = (
39+
shopId: string,
40+
noticeId: string,
41+
): Promise<AxiosResponse<NoticeResponse>> => {
42+
return requestor.get(`/shops/${shopId}/notices/${noticeId}`);
43+
};
44+
45+
/* 가게의 특정 공고 수정 */
46+
export const putNotice = (
47+
shopId: string,
48+
noticeId: string,
49+
payload: NoticePayload,
50+
): Promise<AxiosResponse<NoticeResponse>> => {
51+
return requestor.put(`/shops/${shopId}/notices/${noticeId}`, payload);
52+
};

src/apis/services/shopService.tsx

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
import type { AxiosResponse } from "axios";
2+
import { ShopPayload, ShopResponse } from "src/types";
3+
4+
import requestor from "../client/requestor";
5+
6+
/* 가게 등록 */
7+
export const postShop = (
8+
payload: ShopPayload,
9+
): Promise<AxiosResponse<ShopResponse>> => {
10+
return requestor.post("/shops", payload);
11+
};
12+
13+
/* 가게 정보 조회 */
14+
export const getShop = (
15+
shopId: string,
16+
): Promise<AxiosResponse<ShopResponse>> => {
17+
return requestor.get(`/shops/${shopId}`);
18+
};
19+
20+
/* 가게 정보 수정 */
21+
export const putShop = (
22+
shopId: string,
23+
payload: ShopPayload,
24+
): Promise<AxiosResponse<ShopResponse>> => {
25+
return requestor.put(`/shops/${shopId}`, payload);
26+
};

0 commit comments

Comments
 (0)