"use client"; import { useState, useEffect, useCallback } from "react"; import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query"; import { apiClient } from "@/lib/api/client"; // 템플릿 데이터 인터페이스 export interface TemplateStandard { template_code: string; template_name: string; template_name_eng?: string; description?: string; category: string; icon_name?: string; default_size?: { width: number; height: number; }; layout_config: any; // 템플릿의 컴포넌트 구조 preview_image?: string; sort_order?: number; is_active: string; is_public?: string; company_code: string; created_date?: string; created_by?: string; updated_date?: string; updated_by?: string; } // 템플릿 생성/수정 데이터 export interface TemplateFormData { template_code: string; template_name: string; template_name_eng?: string; description?: string; category: string; icon_name?: string; default_size?: { width: number; height: number; }; layout_config: any; preview_image?: string; sort_order?: number; is_active?: string; is_public?: string; } // API 응답 인터페이스 interface ApiResponse { success: boolean; data?: T; message?: string; error?: string; pagination?: { total: number; page: number; limit: number; totalPages: number; }; } // 쿼리 파라미터 인터페이스 interface TemplateQueryParams { active?: string; category?: string; search?: string; company_code?: string; is_public?: string; page?: number; limit?: number; } /** * 템플릿 관리 훅 */ export const useTemplates = (params?: TemplateQueryParams) => { const queryClient = useQueryClient(); // 템플릿 목록 조회 const { data: templatesData, isLoading, error, refetch, } = useQuery({ queryKey: ["templates", params], queryFn: async (): Promise<{ templates: TemplateStandard[]; pagination: any }> => { const searchParams = new URLSearchParams(); if (params?.active) searchParams.append("active", params.active); if (params?.category) searchParams.append("category", params.category); if (params?.search) searchParams.append("search", params.search); if (params?.company_code) searchParams.append("company_code", params.company_code); if (params?.is_public) searchParams.append("is_public", params.is_public); if (params?.page) searchParams.append("page", params.page.toString()); if (params?.limit) searchParams.append("limit", params.limit.toString()); const response = await apiClient.get(`/admin/template-standards?${searchParams.toString()}`); const result: ApiResponse = response.data; if (!result.success) { throw new Error(result.error || "Failed to fetch templates"); } return { templates: result.data || [], pagination: result.pagination, }; }, staleTime: 5 * 60 * 1000, // 5분간 캐시 유지 cacheTime: 10 * 60 * 1000, // 10분간 메모리 보관 }); const templates = templatesData?.templates || []; const pagination = templatesData?.pagination; // 템플릿 상세 조회 const getTemplate = useCallback(async (templateCode: string) => { const response = await apiClient.get(`/admin/template-standards/${templateCode}`); const result: ApiResponse = response.data; if (!result.success) { throw new Error(result.error || "Failed to fetch template"); } return result.data!; }, []); // 템플릿 생성 const createTemplateMutation = useMutation({ mutationFn: async (data: TemplateFormData): Promise => { const response = await apiClient.post("/admin/template-standards", data); const result: ApiResponse = response.data; if (!result.success) { throw new Error(result.error || "Failed to create template"); } return result.data!; }, onSuccess: () => { // 목록 새로고침 queryClient.invalidateQueries({ queryKey: ["templates"] }); }, }); // 템플릿 수정 const updateTemplateMutation = useMutation({ mutationFn: async ({ templateCode, data, }: { templateCode: string; data: Partial; }): Promise => { const response = await apiClient.put(`/admin/template-standards/${templateCode}`, data); const result: ApiResponse = response.data; if (!result.success) { throw new Error(result.error || "Failed to update template"); } return result.data!; }, onSuccess: () => { // 목록 새로고침 queryClient.invalidateQueries({ queryKey: ["templates"] }); }, }); // 템플릿 삭제 const deleteTemplateMutation = useMutation({ mutationFn: async (templateCode: string): Promise => { const response = await apiClient.delete(`/admin/template-standards/${templateCode}`); const result: ApiResponse = response.data; if (!result.success) { throw new Error(result.error || "Failed to delete template"); } }, onSuccess: () => { // 목록 새로고침 queryClient.invalidateQueries({ queryKey: ["templates"] }); }, }); // 정렬 순서 업데이트 const updateSortOrderMutation = useMutation({ mutationFn: async (templates: { template_code: string; sort_order: number }[]): Promise => { const response = await apiClient.put("/admin/template-standards/sort-order/bulk", { templates }); const result: ApiResponse = response.data; if (!result.success) { throw new Error(result.error || "Failed to update sort order"); } }, onSuccess: () => { // 목록 새로고침 queryClient.invalidateQueries({ queryKey: ["templates"] }); }, }); // 템플릿 복제 const duplicateTemplateMutation = useMutation({ mutationFn: async ({ templateCode, newTemplateCode, newTemplateName, }: { templateCode: string; newTemplateCode: string; newTemplateName: string; }): Promise => { const response = await apiClient.post(`/admin/template-standards/${templateCode}/duplicate`, { new_template_code: newTemplateCode, new_template_name: newTemplateName, }); const result: ApiResponse = response.data; if (!result.success) { throw new Error(result.error || "Failed to duplicate template"); } return result.data!; }, onSuccess: () => { // 목록 새로고침 queryClient.invalidateQueries({ queryKey: ["templates"] }); }, }); // 템플릿 가져오기 const importTemplateMutation = useMutation({ mutationFn: async (templateData: any): Promise => { const response = await apiClient.post("/admin/template-standards/import", templateData); const result: ApiResponse = response.data; if (!result.success) { throw new Error(result.error || "Failed to import template"); } return result.data!; }, onSuccess: () => { // 목록 새로고침 queryClient.invalidateQueries({ queryKey: ["templates"] }); }, }); // 템플릿 내보내기 const exportTemplate = useCallback(async (templateCode: string) => { const response = await apiClient.get(`/admin/template-standards/${templateCode}/export`); const result: ApiResponse = response.data; if (!result.success) { throw new Error(result.error || "Failed to export template"); } return result.data; }, []); // 카테고리 목록 조회 const { data: categories, isLoading: categoriesLoading, error: categoriesError, } = useQuery({ queryKey: ["template-categories"], queryFn: async (): Promise => { const response = await apiClient.get("/admin/template-standards/categories"); const result: ApiResponse = response.data; if (!result.success) { throw new Error(result.error || "Failed to fetch categories"); } return result.data || []; }, staleTime: 10 * 60 * 1000, // 10분간 캐시 유지 }); // 편의 메서드들 const createTemplate = useCallback( (data: TemplateFormData) => { return createTemplateMutation.mutateAsync(data); }, [createTemplateMutation], ); const updateTemplate = useCallback( (templateCode: string, data: Partial) => { return updateTemplateMutation.mutateAsync({ templateCode, data }); }, [updateTemplateMutation], ); const deleteTemplate = useCallback( (templateCode: string) => { return deleteTemplateMutation.mutateAsync(templateCode); }, [deleteTemplateMutation], ); const updateSortOrder = useCallback( (templates: { template_code: string; sort_order: number }[]) => { return updateSortOrderMutation.mutateAsync(templates); }, [updateSortOrderMutation], ); const duplicateTemplate = useCallback( (templateCode: string, newTemplateCode: string, newTemplateName: string) => { return duplicateTemplateMutation.mutateAsync({ templateCode, newTemplateCode, newTemplateName, }); }, [duplicateTemplateMutation], ); const importTemplate = useCallback( (templateData: any) => { return importTemplateMutation.mutateAsync(templateData); }, [importTemplateMutation], ); return { // 데이터 templates, pagination, categories: categories || [], // 로딩 상태 isLoading, categoriesLoading, isCreating: createTemplateMutation.isPending, isUpdating: updateTemplateMutation.isPending, isDeleting: deleteTemplateMutation.isPending, isDuplicating: duplicateTemplateMutation.isPending, isImporting: importTemplateMutation.isPending, isSortOrderUpdating: updateSortOrderMutation.isPending, // 에러 상태 error, categoriesError, createError: createTemplateMutation.error, updateError: updateTemplateMutation.error, deleteError: deleteTemplateMutation.error, duplicateError: duplicateTemplateMutation.error, importError: importTemplateMutation.error, sortOrderError: updateSortOrderMutation.error, // 메서드 getTemplate, createTemplate, updateTemplate, deleteTemplate, updateSortOrder, duplicateTemplate, importTemplate, exportTemplate, refetch, }; };