199 lines
5.0 KiB
TypeScript
199 lines
5.0 KiB
TypeScript
// src/services/feedback.ts
|
|
import { handleApiError } from "./error";
|
|
|
|
// --- 타입 정의 ---
|
|
|
|
interface ApiField {
|
|
key: string;
|
|
name: string;
|
|
format: "text" | "textarea" | "number" | "select";
|
|
status: string;
|
|
}
|
|
|
|
export interface Feedback {
|
|
id: string;
|
|
content: string;
|
|
[key: string]: unknown; // 동적 필드를 위해 인덱스 시그니처 사용
|
|
}
|
|
|
|
export interface Issue {
|
|
id: string;
|
|
name: string;
|
|
}
|
|
|
|
// 동적 폼 필드 스키마 타입
|
|
export interface FeedbackField {
|
|
id: string; // 예: "message", "rating"
|
|
name: string; // 예: "피드백 내용", "평점"
|
|
type: "text" | "textarea" | "number" | "select"; // 렌더링할 입력 타입
|
|
readOnly?: boolean; // UI에서 읽기 전용으로 처리하기 위한 속성
|
|
}
|
|
|
|
// 피드백 생성 요청 타입 (동적 데이터 포함)
|
|
export interface CreateFeedbackRequest {
|
|
issueNames: string[];
|
|
[key: string]: unknown; // 폼 데이터 필드 (예: { 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`;
|
|
|
|
/**
|
|
* 특정 채널의 피드백 목록을 조회합니다.
|
|
*/
|
|
export const getFeedbacks = async (
|
|
projectId: string,
|
|
channelId: string,
|
|
): Promise<Feedback[]> => {
|
|
const url = getFeedbacksSearchApiUrl(projectId, channelId);
|
|
const response = await fetch(url, {
|
|
method: "POST",
|
|
headers: {
|
|
"Content-Type": "application/json",
|
|
},
|
|
body: JSON.stringify({}),
|
|
});
|
|
|
|
if (!response.ok) {
|
|
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 apiFields
|
|
.filter((field: ApiField) => field.status === "ACTIVE")
|
|
.map((field: ApiField) => ({
|
|
id: field.key,
|
|
name: field.name,
|
|
type: field.format,
|
|
}));
|
|
};
|
|
|
|
/**
|
|
* 특정 채널에 새로운 피드백을 생성합니다.
|
|
*/
|
|
export const createFeedback = async (
|
|
projectId: string,
|
|
channelId: string,
|
|
feedbackData: CreateFeedbackRequest,
|
|
): Promise<Feedback> => {
|
|
const url = `/api/projects/${projectId}/channels/${channelId}/feedbacks`;
|
|
const response = await fetch(url, {
|
|
method: "POST",
|
|
headers: {
|
|
"Content-Type": "application/json",
|
|
},
|
|
body: JSON.stringify(feedbackData),
|
|
});
|
|
if (!response.ok) {
|
|
await handleApiError("피드백 생성에 실패했습니다.", response);
|
|
}
|
|
return response.json();
|
|
};
|
|
|
|
/**
|
|
* 프로젝트의 이슈를 검색합니다.
|
|
*/
|
|
export const searchIssues = async (
|
|
projectId: string,
|
|
query: string,
|
|
): Promise<Issue[]> => {
|
|
const url = getIssuesApiUrl(projectId);
|
|
const response = await fetch(url, {
|
|
method: "POST",
|
|
headers: {
|
|
"Content-Type": "application/json",
|
|
},
|
|
body: JSON.stringify({
|
|
query: { name: query },
|
|
limit: 10,
|
|
page: 1,
|
|
sort: { createdAt: "ASC" },
|
|
}),
|
|
});
|
|
if (!response.ok) {
|
|
await handleApiError("이슈 검색에 실패했습니다.", response);
|
|
}
|
|
const result = await response.json();
|
|
return result.items || [];
|
|
};
|
|
|
|
/**
|
|
* 특정 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);
|
|
}
|
|
|
|
const contentLength = response.headers.get("Content-Length");
|
|
if (contentLength === "0" || !contentLength) {
|
|
return {} as Feedback; // 혹은 적절한 기본 객체
|
|
}
|
|
|
|
return response.json();
|
|
};
|