피드백 등록 및 리스트업.

This commit is contained in:
2025-07-30 18:11:01 +09:00
parent ba9b7a27ef
commit e2cb482e5c
28 changed files with 1942 additions and 498 deletions

View File

@@ -1,11 +1,12 @@
// src/services/feedback.ts
import { handleApiError } from "./error";
// --- 타입 정의 ---
// API 응답과 요청 본문에 대한 타입을 정의합니다.
// 실제 API 명세에 따라 더 구체적으로 작성할 수 있습니다.
export interface Feedback {
id: string;
content: string;
// ... 다른 필드들
[key: string]: any; // 동적 필드를 위해 인덱스 시그니처 사용
}
export interface Issue {
@@ -13,47 +14,91 @@ export interface Issue {
name: string;
}
export interface CreateFeedbackRequest {
message: string;
issueNames: string[];
// 동적 폼 필드 스키마 타입
export interface FeedbackField {
id: string; // 예: "message", "rating"
name: string; // 예: "피드백 내용", "평점"
type: "text" | "textarea" | "number" | "select"; // 렌더링할 입력 타입
readOnly?: boolean; // UI에서 읽기 전용으로 처리하기 위한 속성
}
const getApiBaseUrl = (projectId: string, channelId:string) =>
`/api/projects/${projectId}/channels/${channelId}/feedbacks`;
// 피드백 생성 요청 타입 (동적 데이터 포함)
export interface CreateFeedbackRequest {
issueNames: string[];
[key: string]: any; // 폼 데이터 필드 (예: { message: "...", rating: 5 })
}
// --- API 함수 ---
const getFeedbacksSearchApiUrl = (projectId: string, channelId: string) =>
`/api/v2/projects/${projectId}/channels/${channelId}/feedbacks/search`;
const getFeedbackFieldsApiUrl = (projectId: string, channelId: string) =>
`/api/projects/${projectId}/channels/${channelId}/fields`;
const getIssuesApiUrl = (projectId: string) =>
`/api/projects/${projectId}/issues/search`;
/**
* 특정 채널의 피드백 목록을 조회합니다.
* @param projectId 프로젝트 ID
* @param channelId 채널 ID
* @returns 피드백 목록 Promise
*/
export const getFeedbacks = async (
projectId: string,
channelId: string,
): Promise<Feedback[]> => {
const url = getApiBaseUrl(projectId, channelId);
const response = await fetch(url);
const url = getFeedbacksSearchApiUrl(projectId, channelId);
const response = await fetch(url, {
method: "POST",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify({}),
});
if (!response.ok) {
throw new Error("피드백 목록을 불러오는 데 실패했습니다.");
await handleApiError("피드백 목록을 불러오는 데 실패했습니다.", response);
}
const result = await response.json();
return result.items || [];
};
/**
* 특정 채널의 동적 폼 필드 스키마를 조회합니다.
*/
export const getFeedbackFields = async (
projectId: string,
channelId: string,
): Promise<FeedbackField[]> => {
const url = getFeedbackFieldsApiUrl(projectId, channelId);
const response = await fetch(url);
if (!response.ok) {
await handleApiError("피드백 필드 정보를 불러오는 데 실패했습니다.", response);
}
const apiFields = await response.json();
if (!Array.isArray(apiFields)) {
console.error("Error: Fields API response is not an array.", apiFields);
return [];
}
return response.json();
return apiFields
.filter((field: any) => field.status === "ACTIVE")
.map((field: any) => ({
id: field.key,
name: field.name,
type: field.format,
}));
};
/**
* 특정 채널에 새로운 피드백을 생성합니다.
* @param projectId 프로젝트 ID
* @param channelId 채널 ID
* @param feedbackData 생성할 피드백 데이터
* @returns 생성된 피드백 Promise
*/
export const createFeedback = async (
projectId: string,
channelId: string,
feedbackData: CreateFeedbackRequest,
): Promise<Feedback> => {
const url = getApiBaseUrl(projectId, channelId);
const url = `/api/projects/${projectId}/channels/${channelId}/feedbacks`;
const response = await fetch(url, {
method: "POST",
headers: {
@@ -61,25 +106,20 @@ export const createFeedback = async (
},
body: JSON.stringify(feedbackData),
});
if (!response.ok) {
throw new Error("피드백 생성에 실패했습니다.");
await handleApiError("피드백 생성에 실패했습니다.", response);
}
return response.json();
};
/**
* 프로젝트의 이슈를 검색합니다.
* @param projectId 프로젝트 ID
* @param query 검색어
* @returns 이슈 목록 Promise
*/
export const searchIssues = async (
projectId: string,
query: string,
): Promise<Issue[]> => {
const url = `/api/projects/${projectId}/issues/search`;
const url = getIssuesApiUrl(projectId);
const response = await fetch(url, {
method: "POST",
headers: {
@@ -92,14 +132,48 @@ export const searchIssues = async (
sort: { createdAt: "ASC" },
}),
});
if (!response.ok) {
throw new Error("이슈 검색에 실패했습니다.");
await handleApiError("이슈 검색에 실패했습니다.", response);
}
const result = await response.json();
// API 응답이 { items: Issue[] } 형태일 경우를 가정
return result.items || [];
};
// 여기에 다른 API 함수들을 추가할 수 있습니다. (예: updateFeedback, deleteFeedback)
/**
* 특정 ID의 피드백 상세 정보를 조회합니다.
*/
export const getFeedbackById = async (
projectId: string,
channelId: string,
feedbackId: string,
): Promise<Feedback> => {
const url = `/api/projects/${projectId}/channels/${channelId}/feedbacks/${feedbackId}`;
const response = await fetch(url);
if (!response.ok) {
await handleApiError("피드백 상세 정보를 불러오는 데 실패했습니다.", response);
}
return response.json();
};
/**
* 특정 피드백을 수정합니다.
*/
export const updateFeedback = async (
projectId: string,
channelId: string,
feedbackId: string,
feedbackData: Partial<CreateFeedbackRequest>,
): Promise<Feedback> => {
const url = `/api/projects/${projectId}/channels/${channelId}/feedbacks/${feedbackId}`;
const response = await fetch(url, {
method: "PUT",
headers: {
"Content-Type": "application/json",
},
body: JSON.stringify(feedbackData),
});
if (!response.ok) {
await handleApiError("피드백 수정에 실패했습니다.", response);
}
return response.json();
};