Feat: get method API 쿼리 함수 추가

This commit is contained in:
jhynsoo 2024-09-15 00:39:34 +09:00
parent 07eadc03f6
commit 503976b3ee
15 changed files with 194 additions and 135 deletions

View File

@ -1,11 +1,14 @@
import api from '@/api/axiosConfig';
import { MemberResponse, RefreshTokenResponse } from '@/types';
export async function reissueToken() {
return api.post('/auth/reissue', null, { withCredentials: true });
return api.post<RefreshTokenResponse>('/auth/reissue', null, { withCredentials: true }).then(({ data }) => data);
}
export async function fetchProfile() {
return api.get('/auth/profile', {
withCredentials: true,
});
export async function getProfile() {
return api
.get<MemberResponse>('/auth/profile', {
withCredentials: true,
})
.then(({ data }) => data);
}

View File

@ -1,37 +1,42 @@
import api from '@/api/axiosConfig';
import { FolderRequestDTO } from '@/types';
import { FolderRequest, FolderResponse } from '@/types';
export async function fetchFolder(projectId: number, folderId: number, memberId: number) {
return api.get(`/projects/${projectId}/folders/${folderId}`, {
params: { memberId },
});
return api
.get<FolderResponse>(`/projects/${projectId}/folders/${folderId}`, {
params: { memberId },
})
.then(({ data }) => data);
}
export async function updateFolder(
projectId: number,
folderId: number,
memberId: number,
folderData: FolderRequestDTO
) {
return api.put(`/projects/${projectId}/folders/${folderId}`, folderData, {
params: { memberId },
});
export async function updateFolder(projectId: number, folderId: number, memberId: number, folderData: FolderRequest) {
return api
.put(`/projects/${projectId}/folders/${folderId}`, folderData, {
params: { memberId },
})
.then(({ data }) => data);
}
export async function deleteFolder(projectId: number, folderId: number, memberId: number) {
return api.delete(`/projects/${projectId}/folders/${folderId}`, {
params: { memberId },
});
return api
.delete(`/projects/${projectId}/folders/${folderId}`, {
params: { memberId },
})
.then(({ data }) => data);
}
export async function createFolder(projectId: number, memberId: number, folderData: FolderRequestDTO) {
return api.post(`/projects/${projectId}/folders`, folderData, {
params: { memberId },
});
export async function createFolder(projectId: number, memberId: number, folderData: FolderRequest) {
return api
.post(`/projects/${projectId}/folders`, folderData, {
params: { memberId },
})
.then(({ data }) => data);
}
export async function fetchFolderReviewList(projectId: number, folderId: number, memberId: number) {
return api.get(`/projects/${projectId}/folders/${folderId}/review`, {
params: { memberId },
});
export async function getFolderReviewList(projectId: number, folderId: number, memberId: number) {
return api
.get(`/projects/${projectId}/folders/${folderId}/review`, {
params: { memberId },
})
.then(({ data }) => data);
}

View File

@ -1,7 +1,7 @@
import api from '@/api/axiosConfig';
import { ImageMoveRequestDTO, ImageStatusChangeRequestDTO } from '@/types';
import { ImageMoveRequest, ImageStatusChangeRequest } from '@/types';
export async function fetchImage(projectId: number, folderId: number, imageId: number, memberId: number) {
export async function getImage(projectId: number, folderId: number, imageId: number, memberId: number) {
return api.get(`/projects/${projectId}/folders/${folderId}/images/${imageId}`, {
params: { memberId },
});
@ -12,7 +12,7 @@ export async function moveImage(
folderId: number,
imageId: number,
memberId: number,
moveRequest: ImageMoveRequestDTO
moveRequest: ImageMoveRequest
) {
return api.put(`/projects/${projectId}/folders/${folderId}/images/${imageId}`, moveRequest, {
params: { memberId },
@ -30,7 +30,7 @@ export async function changeImageStatus(
folderId: number,
imageId: number,
memberId: number,
statusChangeRequest: ImageStatusChangeRequestDTO
statusChangeRequest: ImageStatusChangeRequest
) {
return api.put(`/projects/${projectId}/folders/${folderId}/images/${imageId}/status`, statusChangeRequest, {
params: { memberId },

View File

@ -1,7 +1,7 @@
import api from '@/api/axiosConfig';
import { LabelingRequestDTO } from '@/types';
import { LabelingRequest } from '@/types';
export async function saveImageLabels(projectId: number, imageId: number, memberId: number, data: LabelingRequestDTO) {
export async function saveImageLabels(projectId: number, imageId: number, memberId: number, data: LabelingRequest) {
return api.post(`/projects/${projectId}/label/image/${imageId}`, data, {
params: { memberId },
});

View File

@ -1,70 +1,84 @@
import api from '@/api/axiosConfig';
export async function getProjectApi(projectId: number, memberId: number) {
return api.get(`/projects/${projectId}`, {
params: { memberId },
});
export async function getProject(projectId: number, memberId: number) {
return api
.get(`/projects/${projectId}`, {
params: { memberId },
})
.then(({ data }) => data);
}
export async function updateProjectApi(
export async function updateProject(
projectId: number,
memberId: number,
data: { title: string; projectType: 'classification' | 'detection' | 'segmentation' }
) {
return api.put(`/projects/${projectId}`, data, {
params: { memberId },
});
return api
.put(`/projects/${projectId}`, data, {
params: { memberId },
})
.then(({ data }) => data);
}
export async function deleteProjectApi(projectId: number, memberId: number) {
return api.delete(`/projects/${projectId}`, {
params: { memberId },
});
export async function deleteProject(projectId: number, memberId: number) {
return api
.delete(`/projects/${projectId}`, {
params: { memberId },
})
.then(({ data }) => data);
}
export async function addProjectMemberApi(
export async function addProjectMember(
projectId: number,
memberId: number,
newMemberId: number,
privilegeType: string
) {
return api.post(
`/projects/${projectId}/members`,
{ memberId: newMemberId, privilegeType },
{
return api
.post(
`/projects/${projectId}/members`,
{ memberId: newMemberId, privilegeType },
{
params: { memberId },
}
)
.then(({ data }) => data);
}
export async function removeProjectMember(projectId: number, memberId: number, targetMemberId: number) {
return api
.delete(`/projects/${projectId}/members`, {
params: { memberId },
}
);
data: { memberId: targetMemberId },
})
.then(({ data }) => data);
}
export async function removeProjectMemberApi(projectId: number, memberId: number, targetMemberId: number) {
return api.delete(`/projects/${projectId}/members`, {
params: { memberId },
data: { memberId: targetMemberId },
});
}
export async function getAllProjectsApi(
export async function getAllProjects(
workspaceId: number,
memberId: number,
lastProjectId?: number,
limit: number = 10
) {
return api.get(`/workspaces/${workspaceId}/projects`, {
params: {
memberId,
lastProjectId,
limit,
},
});
return api
.get(`/workspaces/${workspaceId}/projects`, {
params: {
memberId,
lastProjectId,
limit,
},
})
.then(({ data }) => data);
}
export async function createProjectApi(
export async function createProject(
workspaceId: number,
memberId: number,
data: { title: string; projectType: 'classification' | 'detection' | 'segmentation' }
) {
return api.post(`/workspaces/${workspaceId}/projects`, data, {
params: { memberId },
});
return api
.post(`/workspaces/${workspaceId}/projects`, data, {
params: { memberId },
})
.then(({ data }) => data);
}

View File

@ -14,6 +14,7 @@ export async function uploadFilesToProject(
formData.append('files', file);
});
// TODO: api.post()를 return하고 사이드 이펙트는 외부에서 처리하도록 수정
return api
.post('/projects/{project_id}', formData, {
onUploadProgress: (progressEvent: AxiosProgressEvent) => {

View File

@ -1,5 +1,5 @@
import api from '@/api/axiosConfig';
import { WorkspaceRequestDTO } from '@/types';
import { WorkspaceRequest } from '@/types';
export async function fetchWorkspaceList(memberId: number, lastWorkspaceId?: number, limit?: number) {
return api.get('/workspaces', {
@ -13,7 +13,7 @@ export async function fetchWorkspace(workspaceId: number, memberId: number) {
});
}
export async function updateWorkspace(workspaceId: number, memberId: number, data: WorkspaceRequestDTO) {
export async function updateWorkspace(workspaceId: number, memberId: number, data: WorkspaceRequest) {
return api.put(`/workspaces/${workspaceId}`, data, {
params: { memberId },
});
@ -25,7 +25,7 @@ export async function deleteWorkspace(workspaceId: number, memberId: number) {
});
}
export async function createWorkspace(memberId: number, data: WorkspaceRequestDTO) {
export async function createWorkspace(memberId: number, data: WorkspaceRequest) {
return api.post('/workspaces', data, {
params: { memberId },
});

View File

@ -1,47 +1,31 @@
import { useQuery, UseQueryResult, useMutation, useQueryClient, UseMutationResult } from '@tanstack/react-query';
import { useMutation, useQueryClient } from '@tanstack/react-query';
import { AxiosError } from 'axios';
import useAuthStore from '@/stores/useAuthStore';
import { reissueTokenApi, fetchProfileApi } from '@/api/authApi';
import { SuccessResponse, RefreshTokenResponseDTO, MemberResponseDTO, CustomError } from '@/types';
import { reissueToken, getProfile } from '@/api/authApi';
import { CustomError } from '@/types';
import { useState, useEffect } from 'react';
import useProfileQuery from '@/queries/useProfileQuery';
export const useReissueToken = (): UseMutationResult<
SuccessResponse<RefreshTokenResponseDTO>,
AxiosError<CustomError>
> => {
export const useReissueToken = () => {
const queryClient = useQueryClient();
const { setLoggedIn } = useAuthStore();
return useMutation({
mutationFn: reissueTokenApi,
mutationFn: reissueToken,
onSuccess: (data) => {
if (data.isSuccess && data.data) {
setLoggedIn(true, data.data.accessToken);
queryClient.invalidateQueries({ queryKey: ['profile'] });
} else {
console.error('토큰 재발급 응답 오류:', data.message);
}
},
onError: (error) => {
console.error('토큰 재발급 실패:', error?.response?.data?.message || '알 수 없는 오류');
setLoggedIn(true, data.accessToken);
queryClient.invalidateQueries({ queryKey: ['profile'] });
},
});
};
export const useProfile = (): UseQueryResult<SuccessResponse<MemberResponseDTO>, AxiosError<CustomError>> => {
const { accessToken, setProfile } = useAuthStore();
const query = useQuery<SuccessResponse<MemberResponseDTO>, AxiosError<CustomError>>({
queryKey: ['profile'],
queryFn: fetchProfileApi,
enabled: !!accessToken,
select: (data) => data,
});
export const useProfile = () => {
const { setProfile } = useAuthStore();
const query = useProfileQuery();
// TODO: query.data가 변경될 때마다 setProfile을 호출하여 profile 업데이트, useEffect 제거
useEffect(() => {
if (query.data?.isSuccess) {
setProfile(query.data.data);
}
setProfile(query.data);
}, [query.data, setProfile]);
return query;
@ -53,14 +37,10 @@ export const useFetchProfile = () => {
useEffect(() => {
if (!profile && !isFetched) {
fetchProfileApi()
getProfile()
.then((data) => {
if (data.isSuccess && data.data) {
setProfile(data.data);
setIsFetched(true);
} else {
console.error('프로필 응답 오류:', data.message);
}
setProfile(data);
setIsFetched(true);
})
.catch((error: AxiosError<CustomError>) => {
alert('프로필을 가져오는 중 오류가 발생했습니다. 다시 시도해주세요.');

View File

@ -0,0 +1,9 @@
import { fetchFolder } from '@/api/folderApi';
import { useSuspenseQuery } from '@tanstack/react-query';
export default function useFolderQuery(projectId: number, folderId: number, memberId: number) {
return useSuspenseQuery({
queryKey: ['folder', projectId, folderId, memberId],
queryFn: () => fetchFolder(projectId, folderId, memberId),
});
}

View File

@ -0,0 +1,9 @@
import { getFolderReviewList } from '@/api/folderApi';
import { useSuspenseQuery } from '@tanstack/react-query';
export function useFolderReviewListQuery(projectId: number, folderId: number, memberId: number) {
return useSuspenseQuery({
queryKey: ['folderReviewList', projectId, folderId, memberId],
queryFn: () => getFolderReviewList(projectId, folderId, memberId),
});
}

View File

@ -0,0 +1,9 @@
import { getProfile } from '@/api/authApi';
import { useSuspenseQuery } from '@tanstack/react-query';
export default function useProfileQuery() {
return useSuspenseQuery({
queryKey: ['profile'],
queryFn: getProfile,
});
}

View File

@ -0,0 +1,9 @@
import { getProject } from '@/api/projectApi';
import { useSuspenseQuery } from '@tanstack/react-query';
export default function useProjectQuery(projectId: number, memberId: number) {
return useSuspenseQuery({
queryKey: ['project', projectId, memberId],
queryFn: () => getProject(projectId, memberId),
});
}

View File

@ -0,0 +1,9 @@
import { fetchWorkspaceList } from '@/api/workspaceApi';
import { useSuspenseQuery } from '@tanstack/react-query';
export default function useWorkspaceListQuery(memberId: number, lastWorkspaceId?: number, limit?: number) {
return useSuspenseQuery({
queryKey: ['workspaceList'],
queryFn: () => fetchWorkspaceList(memberId, lastWorkspaceId, limit),
});
}

View File

@ -0,0 +1,9 @@
import { fetchWorkspace } from '@/api/workspaceApi';
import { useSuspenseQuery } from '@tanstack/react-query';
export default function useWorkspaceQuery(workspaceId: number, memberId: number) {
return useSuspenseQuery({
queryKey: ['workspace', workspaceId, memberId],
queryFn: () => fetchWorkspace(workspaceId, memberId),
});
}

View File

@ -34,50 +34,50 @@ export type Label = {
coordinates: Array<[number, number]>;
};
export interface FolderRequestDTO {
export interface FolderRequest {
title: string;
parentId: number;
}
export interface ChildFolderDTO {
export interface ChildFolder {
id: number;
title: string;
}
export interface FolderResponseDTO {
export interface FolderResponse {
id: number;
title: string;
images: ImageResponseDTO[];
children: ChildFolderDTO[];
images: ImageResponse[];
children: ChildFolder[];
}
export interface ImageResponseDTO {
export interface ImageResponse {
id: number;
imageTitle: string;
imageUrl: string;
status: 'PENDING' | 'IN_PROGRESS' | 'NEED_REVIEW' | 'COMPLETED';
}
export interface ImageMoveRequestDTO {
export interface ImageMoveRequest {
moveFolderId: number;
}
export interface ImageStatusChangeRequestDTO {
export interface ImageStatusChangeRequest {
labelStatus: 'PENDING' | 'IN_PROGRESS' | 'NEED_REVIEW' | 'COMPLETED';
}
export interface MemberResponseDTO {
export interface MemberResponse {
id: number;
nickname: string;
profileImage: string;
}
export interface WorkspaceRequestDTO {
export interface WorkspaceRequest {
title: string;
content: string;
}
export interface WorkspaceResponseDTO {
export interface WorkspaceResponse {
id: number;
memberId: string;
title: string;
@ -86,8 +86,8 @@ export interface WorkspaceResponseDTO {
updatedAt: string;
}
export interface WorkspaceListResponseDTO {
workspaceResponses: WorkspaceResponseDTO[];
export interface WorkspaceListResponse {
workspaceResponses: WorkspaceResponse[];
}
export interface SuccessResponse<T> {
@ -98,11 +98,13 @@ export interface SuccessResponse<T> {
errors: CustomError[];
isSuccess: boolean;
}
export interface ProjectRequestDTO {
export interface ProjectRequest {
title: string;
projectType: 'classification' | 'detection' | 'segmentation';
}
export interface ProjectResponseDTO {
export interface ProjectResponse {
id: number;
title: string;
workspaceId: number;
@ -111,8 +113,8 @@ export interface ProjectResponseDTO {
updatedAt: string;
}
export interface ProjectListResponseDTO {
workspaceResponses: ProjectResponseDTO[];
export interface ProjectListResponse {
workspaceResponses: ProjectResponse[];
}
export interface CustomError {
@ -140,17 +142,17 @@ export interface BaseResponse<T> {
isSuccess: boolean;
}
export interface RefreshTokenResponseDTO {
export interface RefreshTokenResponse {
accessToken: string;
}
export interface CommentRequestDTO {
export interface CommentRequest {
content: string;
positionX: number;
positionY: number;
}
export interface CommentResponseDTO {
export interface CommentResponse {
id: number;
memberId: number;
memberNickname: string;
@ -161,18 +163,18 @@ export interface CommentResponseDTO {
createTime: string; // 작성 일자 (ISO 8601 형식)
}
export interface ProjectMemberRequestDTO {
export interface ProjectMemberRequest {
memberId: number;
privilegeType: 'ADMIN' | 'MANAGER' | 'EDITOR' | 'VIEWER';
}
export interface LabelingRequestDTO {
export interface LabelingRequest {
memberId: number;
projectId: number;
imageId: number;
}
export interface AutoLabelingResponseDTO {
export interface AutoLabelingResponse {
imageId: number;
imageUrl: string;
data: string;