웹타입 컴포넌트 분리작업
This commit is contained in:
314
frontend/hooks/admin/useButtonActions.ts
Normal file
314
frontend/hooks/admin/useButtonActions.ts
Normal file
@@ -0,0 +1,314 @@
|
||||
"use client";
|
||||
|
||||
import { useState, useEffect, useCallback } from "react";
|
||||
import { useQuery, useMutation, useQueryClient } from "@tanstack/react-query";
|
||||
|
||||
// 버튼 액션 데이터 인터페이스
|
||||
export interface ButtonActionStandard {
|
||||
action_type: string;
|
||||
action_name: string;
|
||||
action_name_eng?: string;
|
||||
description?: string;
|
||||
category: string;
|
||||
default_text?: string;
|
||||
default_text_eng?: string;
|
||||
default_icon?: string;
|
||||
default_color?: string;
|
||||
default_variant?: string;
|
||||
confirmation_required: boolean;
|
||||
confirmation_message?: string;
|
||||
validation_rules?: any;
|
||||
action_config?: any;
|
||||
sort_order?: number;
|
||||
is_active: string;
|
||||
created_date?: string;
|
||||
created_by?: string;
|
||||
updated_date?: string;
|
||||
updated_by?: string;
|
||||
}
|
||||
|
||||
// 버튼 액션 생성/수정 데이터
|
||||
export interface ButtonActionFormData {
|
||||
action_type: string;
|
||||
action_name: string;
|
||||
action_name_eng?: string;
|
||||
description?: string;
|
||||
category: string;
|
||||
default_text?: string;
|
||||
default_text_eng?: string;
|
||||
default_icon?: string;
|
||||
default_color?: string;
|
||||
default_variant?: string;
|
||||
confirmation_required?: boolean;
|
||||
confirmation_message?: string;
|
||||
validation_rules?: any;
|
||||
action_config?: any;
|
||||
sort_order?: number;
|
||||
is_active?: string;
|
||||
}
|
||||
|
||||
// API 응답 인터페이스
|
||||
interface ApiResponse<T> {
|
||||
success: boolean;
|
||||
data?: T;
|
||||
message?: string;
|
||||
error?: string;
|
||||
}
|
||||
|
||||
// 쿼리 파라미터 인터페이스
|
||||
interface ButtonActionQueryParams {
|
||||
active?: string;
|
||||
category?: string;
|
||||
search?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* 버튼 액션 관리 훅
|
||||
*/
|
||||
export const useButtonActions = (params?: ButtonActionQueryParams) => {
|
||||
const queryClient = useQueryClient();
|
||||
|
||||
// 버튼 액션 목록 조회
|
||||
const {
|
||||
data: buttonActions,
|
||||
isLoading,
|
||||
error,
|
||||
refetch,
|
||||
} = useQuery({
|
||||
queryKey: ["buttonActions", params],
|
||||
queryFn: async (): Promise<ButtonActionStandard[]> => {
|
||||
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);
|
||||
|
||||
const response = await fetch(
|
||||
`/api/admin/button-actions?${searchParams.toString()}`,
|
||||
{
|
||||
headers: {
|
||||
Authorization: `Bearer ${localStorage.getItem("token")}`,
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
}
|
||||
);
|
||||
|
||||
if (!response.ok) {
|
||||
throw new Error(`HTTP error! status: ${response.status}`);
|
||||
}
|
||||
|
||||
const result: ApiResponse<ButtonActionStandard[]> = await response.json();
|
||||
|
||||
if (!result.success) {
|
||||
throw new Error(result.error || "Failed to fetch button actions");
|
||||
}
|
||||
|
||||
return result.data || [];
|
||||
},
|
||||
staleTime: 5 * 60 * 1000, // 5분간 캐시 유지
|
||||
cacheTime: 10 * 60 * 1000, // 10분간 메모리 보관
|
||||
});
|
||||
|
||||
// 버튼 액션 생성
|
||||
const createButtonActionMutation = useMutation({
|
||||
mutationFn: async (
|
||||
data: ButtonActionFormData
|
||||
): Promise<ButtonActionStandard> => {
|
||||
const response = await fetch("/api/admin/button-actions", {
|
||||
method: "POST",
|
||||
headers: {
|
||||
Authorization: `Bearer ${localStorage.getItem("token")}`,
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify(data),
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
const errorData = await response.json();
|
||||
throw new Error(
|
||||
errorData.message || `HTTP error! status: ${response.status}`
|
||||
);
|
||||
}
|
||||
|
||||
const result: ApiResponse<ButtonActionStandard> = await response.json();
|
||||
|
||||
if (!result.success) {
|
||||
throw new Error(result.error || "Failed to create button action");
|
||||
}
|
||||
|
||||
return result.data!;
|
||||
},
|
||||
onSuccess: () => {
|
||||
// 목록 새로고침
|
||||
queryClient.invalidateQueries({ queryKey: ["buttonActions"] });
|
||||
},
|
||||
});
|
||||
|
||||
// 버튼 액션 수정
|
||||
const updateButtonActionMutation = useMutation({
|
||||
mutationFn: async ({
|
||||
actionType,
|
||||
data,
|
||||
}: {
|
||||
actionType: string;
|
||||
data: Partial<ButtonActionFormData>;
|
||||
}): Promise<ButtonActionStandard> => {
|
||||
const response = await fetch(`/api/admin/button-actions/${actionType}`, {
|
||||
method: "PUT",
|
||||
headers: {
|
||||
Authorization: `Bearer ${localStorage.getItem("token")}`,
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify(data),
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
const errorData = await response.json();
|
||||
throw new Error(
|
||||
errorData.message || `HTTP error! status: ${response.status}`
|
||||
);
|
||||
}
|
||||
|
||||
const result: ApiResponse<ButtonActionStandard> = await response.json();
|
||||
|
||||
if (!result.success) {
|
||||
throw new Error(result.error || "Failed to update button action");
|
||||
}
|
||||
|
||||
return result.data!;
|
||||
},
|
||||
onSuccess: () => {
|
||||
// 목록 새로고침
|
||||
queryClient.invalidateQueries({ queryKey: ["buttonActions"] });
|
||||
},
|
||||
});
|
||||
|
||||
// 버튼 액션 삭제
|
||||
const deleteButtonActionMutation = useMutation({
|
||||
mutationFn: async (actionType: string): Promise<void> => {
|
||||
const response = await fetch(`/api/admin/button-actions/${actionType}`, {
|
||||
method: "DELETE",
|
||||
headers: {
|
||||
Authorization: `Bearer ${localStorage.getItem("token")}`,
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
});
|
||||
|
||||
if (!response.ok) {
|
||||
const errorData = await response.json();
|
||||
throw new Error(
|
||||
errorData.message || `HTTP error! status: ${response.status}`
|
||||
);
|
||||
}
|
||||
|
||||
const result: ApiResponse<void> = await response.json();
|
||||
|
||||
if (!result.success) {
|
||||
throw new Error(result.error || "Failed to delete button action");
|
||||
}
|
||||
},
|
||||
onSuccess: () => {
|
||||
// 목록 새로고침
|
||||
queryClient.invalidateQueries({ queryKey: ["buttonActions"] });
|
||||
},
|
||||
});
|
||||
|
||||
// 정렬 순서 업데이트
|
||||
const updateSortOrderMutation = useMutation({
|
||||
mutationFn: async (
|
||||
buttonActions: { action_type: string; sort_order: number }[]
|
||||
): Promise<void> => {
|
||||
const response = await fetch(
|
||||
"/api/admin/button-actions/sort-order/bulk",
|
||||
{
|
||||
method: "PUT",
|
||||
headers: {
|
||||
Authorization: `Bearer ${localStorage.getItem("token")}`,
|
||||
"Content-Type": "application/json",
|
||||
},
|
||||
body: JSON.stringify({ buttonActions }),
|
||||
}
|
||||
);
|
||||
|
||||
if (!response.ok) {
|
||||
const errorData = await response.json();
|
||||
throw new Error(
|
||||
errorData.message || `HTTP error! status: ${response.status}`
|
||||
);
|
||||
}
|
||||
|
||||
const result: ApiResponse<void> = await response.json();
|
||||
|
||||
if (!result.success) {
|
||||
throw new Error(result.error || "Failed to update sort order");
|
||||
}
|
||||
},
|
||||
onSuccess: () => {
|
||||
// 목록 새로고침
|
||||
queryClient.invalidateQueries({ queryKey: ["buttonActions"] });
|
||||
},
|
||||
});
|
||||
|
||||
// 편의 메서드들
|
||||
const createButtonAction = useCallback(
|
||||
(data: ButtonActionFormData) => {
|
||||
return createButtonActionMutation.mutateAsync(data);
|
||||
},
|
||||
[createButtonActionMutation]
|
||||
);
|
||||
|
||||
const updateButtonAction = useCallback(
|
||||
(actionType: string, data: Partial<ButtonActionFormData>) => {
|
||||
return updateButtonActionMutation.mutateAsync({ actionType, data });
|
||||
},
|
||||
[updateButtonActionMutation]
|
||||
);
|
||||
|
||||
const deleteButtonAction = useCallback(
|
||||
(actionType: string) => {
|
||||
return deleteButtonActionMutation.mutateAsync(actionType);
|
||||
},
|
||||
[deleteButtonActionMutation]
|
||||
);
|
||||
|
||||
const updateSortOrder = useCallback(
|
||||
(buttonActions: { action_type: string; sort_order: number }[]) => {
|
||||
return updateSortOrderMutation.mutateAsync(buttonActions);
|
||||
},
|
||||
[updateSortOrderMutation]
|
||||
);
|
||||
|
||||
return {
|
||||
// 데이터
|
||||
buttonActions: buttonActions || [],
|
||||
|
||||
// 로딩 상태
|
||||
isLoading,
|
||||
isCreating: createButtonActionMutation.isPending,
|
||||
isUpdating: updateButtonActionMutation.isPending,
|
||||
isDeleting: deleteButtonActionMutation.isPending,
|
||||
isSortingUpdating: updateSortOrderMutation.isPending,
|
||||
|
||||
// 에러
|
||||
error,
|
||||
createError: createButtonActionMutation.error,
|
||||
updateError: updateButtonActionMutation.error,
|
||||
deleteError: deleteButtonActionMutation.error,
|
||||
sortError: updateSortOrderMutation.error,
|
||||
|
||||
// 액션
|
||||
createButtonAction,
|
||||
updateButtonAction,
|
||||
deleteButtonAction,
|
||||
updateSortOrder,
|
||||
refetch,
|
||||
|
||||
// 상태 초기화
|
||||
resetCreateError: createButtonActionMutation.reset,
|
||||
resetUpdateError: updateButtonActionMutation.reset,
|
||||
resetDeleteError: deleteButtonActionMutation.reset,
|
||||
resetSortError: updateSortOrderMutation.reset,
|
||||
};
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user