// 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 => { 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 => { 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 => { 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 => { 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 => { 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, ): Promise => { 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(); };