Feat: 리뷰 관련 훅, 쿼리 구현
This commit is contained in:
parent
04755eb526
commit
2cb13477fb
60
frontend/src/api/reviewApi.ts
Normal file
60
frontend/src/api/reviewApi.ts
Normal 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);
|
||||
}
|
57
frontend/src/hooks/useReviewHooks.ts
Normal file
57
frontend/src/hooks/useReviewHooks.ts
Normal 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] });
|
||||
},
|
||||
});
|
||||
};
|
@ -155,6 +155,93 @@ export const handlers = [
|
||||
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
|
||||
http.get('/api/projects/:projectId/folders/:folderId', ({ params }) => {
|
||||
const { folderId } = params;
|
||||
|
9
frontend/src/queries/useReviewByStatusQuery.ts
Normal file
9
frontend/src/queries/useReviewByStatusQuery.ts
Normal 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),
|
||||
});
|
||||
}
|
9
frontend/src/queries/useReviewDetailQuery.ts
Normal file
9
frontend/src/queries/useReviewDetailQuery.ts
Normal 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),
|
||||
});
|
||||
}
|
Loading…
Reference in New Issue
Block a user