Feat: 리뷰 관련 훅, 쿼리 구현

This commit is contained in:
정현조 2024-09-18 20:25:20 +09:00
parent 04755eb526
commit 2cb13477fb
5 changed files with 222 additions and 0 deletions

View File

@ -0,0 +1,60 @@
import api from '@/api/axiosConfig';
import { ReviewDetailResponse, ReviewRequest, ReviewResponse } from '@/types';
// 리뷰 단건 조회
export async function getReviewDetail(projectId: number, reviewId: number, memberId: number) {
return api
.get<ReviewDetailResponse>(`/projects/${projectId}/reviews/${reviewId}`, {
params: { memberId },
})
.then(({ data }) => data);
}
// 리뷰 생성
export async function createReview(projectId: number, memberId: number, reviewData: ReviewRequest) {
return api
.post<ReviewResponse>(`/projects/${projectId}/reviews`, reviewData, {
params: { memberId },
})
.then(({ data }) => data);
}
// 리뷰 수정
export async function updateReview(projectId: number, reviewId: number, memberId: number, reviewData: ReviewRequest) {
return api
.put<ReviewResponse>(`/projects/${projectId}/reviews/${reviewId}`, reviewData, {
params: { memberId },
})
.then(({ data }) => data);
}
// 리뷰 삭제
export async function deleteReview(projectId: number, reviewId: number, memberId: number) {
return api
.delete(`/projects/${projectId}/reviews/${reviewId}`, {
params: { memberId },
})
.then(({ data }) => data);
}
// 리뷰 상태 변경
export async function updateReviewStatus(projectId: number, reviewId: number, memberId: number, reviewStatus: string) {
return api
.put<ReviewResponse>(
`/projects/${projectId}/reviews/${reviewId}/status`,
{ reviewStatus },
{
params: { memberId },
}
)
.then(({ data }) => data);
}
// 리뷰 상태별 조회
export async function getReviewByStatus(projectId: number, memberId: number, reviewStatus: string) {
return api
.get<ReviewResponse[]>(`/projects/${projectId}/reviews`, {
params: { memberId, reviewStatus },
})
.then(({ data }) => data);
}

View File

@ -0,0 +1,57 @@
import { useMutation, useQueryClient } from '@tanstack/react-query';
import { createReview, updateReview, deleteReview, updateReviewStatus } from '@/api/reviewApi';
import { ReviewRequest, ReviewResponse } from '@/types';
// 리뷰 생성 훅
export const useCreateReview = () => {
const queryClient = useQueryClient();
return useMutation<ReviewResponse, Error, { projectId: number; memberId: number; reviewData: ReviewRequest }>({
mutationFn: ({ projectId, memberId, reviewData }) => createReview(projectId, memberId, reviewData),
onSuccess: (_, { projectId, memberId }) => {
queryClient.invalidateQueries({ queryKey: ['reviewList', projectId, memberId] });
},
});
};
// 리뷰 수정 훅
export const useUpdateReview = () => {
const queryClient = useQueryClient();
return useMutation<
ReviewResponse,
Error,
{ projectId: number; reviewId: number; memberId: number; reviewData: ReviewRequest }
>({
mutationFn: ({ projectId, reviewId, memberId, reviewData }) =>
updateReview(projectId, reviewId, memberId, reviewData),
onSuccess: (_, { projectId, reviewId }) => {
queryClient.invalidateQueries({ queryKey: ['reviewDetail', projectId, reviewId] });
},
});
};
// 리뷰 삭제 훅
export const useDeleteReview = () => {
const queryClient = useQueryClient();
return useMutation<void, Error, { projectId: number; reviewId: number; memberId: number }>({
mutationFn: ({ projectId, reviewId, memberId }) => deleteReview(projectId, reviewId, memberId),
onSuccess: (_, { projectId, reviewId }) => {
queryClient.invalidateQueries({ queryKey: ['reviewDetail', projectId, reviewId] });
},
});
};
// 리뷰 상태 변경 훅
export const useUpdateReviewStatus = () => {
const queryClient = useQueryClient();
return useMutation<
ReviewResponse,
Error,
{ projectId: number; reviewId: number; memberId: number; reviewStatus: string }
>({
mutationFn: ({ projectId, reviewId, memberId, reviewStatus }) =>
updateReviewStatus(projectId, reviewId, memberId, reviewStatus),
onSuccess: (_, { projectId, reviewId }) => {
queryClient.invalidateQueries({ queryKey: ['reviewDetail', projectId, reviewId] });
},
});
};

View File

@ -155,6 +155,93 @@ export const handlers = [
return HttpResponse.json({}); return HttpResponse.json({});
}), }),
http.post('/api/projects/:projectId/label/auto', () => {
const response: AutoLabelingResponse = {
imageId: 1,
imageUrl: 'image-url.jpg',
data: `{
"version": "0.1.0",
"task_type": "cls",
"shapes": [
{
"label": "NG",
"color": "#FF0000",
"points": [[0, 0]],
"group_id": null,
"shape_type": "point",
"flags": {}
}
],
"split": "none",
"imageHeight": 2000,
"imageWidth": 4000,
"imageDepth": 4
}`,
};
return HttpResponse.json(response);
}),
// DELETE: 프로젝트 멤버 제거 핸들러
http.delete('/api/projects/:projectId/members', ({ params }) => {
const { projectId } = params;
return HttpResponse.json({ message: `프로젝트 ${projectId}에서 멤버 제거 성공` });
}),
// PUT: 프로젝트 멤버 권한 수정 핸들러
http.put('/api/projects/:projectId/members', () => {
return HttpResponse.json({});
}),
// POST: 워크스페이스 멤버 추가 핸들러
http.post('/api/workspaces/:workspaceId/members/:memberId', ({ params }) => {
const { workspaceId, memberId } = params;
if (!workspaceId || !memberId) {
const errorResponse: ErrorResponse = {
status: 400,
code: 1002,
message: '잘못된 요청입니다. 요청을 확인해주세요.',
isSuccess: false,
};
return HttpResponse.json(errorResponse, { status: 400 });
}
// 성공 응답
const response: WorkspaceResponse = {
id: parseInt(workspaceId as string, 10),
memberId: parseInt(memberId as string, 10),
title: 'Workspace 1',
content: 'Workspace for testing',
createdAt: new Date().toISOString(),
updatedAt: new Date().toISOString(),
};
return HttpResponse.json(response, { status: 200 });
}),
// GET: 프로젝트 멤버 리스트 조회 핸들러 (가상)
// 실제 구현 시 API 경로와 메서드를 확인 후 업데이트 필요
http.get('/api/projects/:projectId/members', () => {
const members: MemberResponse[] = [
{ id: 1, nickname: 'admin', profileImage: 'admin.jpg' },
{ id: 2, nickname: 'editor', profileImage: 'editor.jpg' },
{ id: 3, nickname: 'viewer', profileImage: 'viewer.jpg' },
];
return HttpResponse.json(members);
}),
// GET: 워크스페이스 멤버 리스트 조회 핸들러 (가상)
// 실제 구현 시 API 경로와 메서드를 확인 후 업데이트 필요
http.get('/api/workspaces/:workspaceId/members', () => {
const members: MemberResponse[] = [
{ id: 1, nickname: 'admin', profileImage: 'admin.jpg' },
{ id: 2, nickname: 'editor', profileImage: 'editor.jpg' },
{ id: 3, nickname: 'viewer', profileImage: 'viewer.jpg' },
];
return HttpResponse.json(members);
}),
// Folder and Image Handlers // Folder and Image Handlers
http.get('/api/projects/:projectId/folders/:folderId', ({ params }) => { http.get('/api/projects/:projectId/folders/:folderId', ({ params }) => {
const { folderId } = params; const { folderId } = params;

View File

@ -0,0 +1,9 @@
import { getReviewByStatus } from '@/api/reviewApi';
import { useSuspenseQuery } from '@tanstack/react-query';
export default function useReviewByStatusQuery(projectId: number, memberId: number, reviewStatus: string) {
return useSuspenseQuery({
queryKey: ['reviewByStatus', projectId, reviewStatus],
queryFn: () => getReviewByStatus(projectId, memberId, reviewStatus),
});
}

View File

@ -0,0 +1,9 @@
import { getReviewDetail } from '@/api/reviewApi';
import { useSuspenseQuery } from '@tanstack/react-query';
export default function useReviewDetailQuery(projectId: number, reviewId: number, memberId: number) {
return useSuspenseQuery({
queryKey: ['reviewDetail', projectId, reviewId, memberId],
queryFn: () => getReviewDetail(projectId, reviewId, memberId),
});
}