"use client"; import React, { useState, useEffect } from "react"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Label } from "@/components/ui/label"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select"; import { Textarea } from "@/components/ui/textarea"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { Separator } from "@/components/ui/separator"; import { Badge } from "@/components/ui/badge"; import { Save, X, Trash2, Edit, Plus, RotateCcw, Send, ExternalLink, MousePointer, Settings, AlertTriangle, } from "lucide-react"; import { ButtonActionType, ButtonTypeConfig, WidgetComponent, ScreenDefinition } from "@/types/screen"; import { screenApi } from "@/lib/api/screen"; interface ButtonConfigPanelProps { component: WidgetComponent; onUpdateComponent: (updates: Partial) => void; } const actionTypeOptions: { value: ButtonActionType; label: string; icon: React.ReactNode; color: string }[] = [ { value: "save", label: "저장", icon: , color: "#3b82f6" }, { value: "delete", label: "삭제", icon: , color: "#ef4444" }, { value: "edit", label: "수정", icon: , color: "#f59e0b" }, { value: "add", label: "추가", icon: , color: "#10b981" }, { value: "search", label: "검색", icon: , color: "#8b5cf6" }, { value: "reset", label: "초기화", icon: , color: "#6b7280" }, { value: "submit", label: "제출", icon: , color: "#059669" }, { value: "close", label: "닫기", icon: , color: "#6b7280" }, { value: "popup", label: "모달 열기", icon: , color: "#8b5cf6" }, { value: "navigate", label: "페이지 이동", icon: , color: "#0ea5e9" }, { value: "custom", label: "사용자 정의", icon: , color: "#64748b" }, ]; export const ButtonConfigPanel: React.FC = ({ component, onUpdateComponent }) => { const config = (component.webTypeConfig as ButtonTypeConfig) || {}; // 로컬 상태 관리 const [localConfig, setLocalConfig] = useState(() => { const defaultConfig = { actionType: "custom" as ButtonActionType, variant: "default" as ButtonVariant, }; return { ...defaultConfig, ...config, // 저장된 값이 기본값을 덮어씀 }; }); // 화면 목록 상태 const [screens, setScreens] = useState([]); const [screensLoading, setScreensLoading] = useState(false); // 화면 목록 로드 함수 const loadScreens = async () => { try { setScreensLoading(true); const response = await screenApi.getScreens({ size: 1000 }); // 모든 화면 가져오기 setScreens(response.data); } catch (error) { console.error("화면 목록 로드 실패:", error); } finally { setScreensLoading(false); } }; // 모달 또는 네비게이션 액션 타입일 때 화면 목록 로드 useEffect(() => { if (localConfig.actionType === "popup" || localConfig.actionType === "navigate") { loadScreens(); } }, [localConfig.actionType]); // 컴포넌트 변경 시 로컬 상태 동기화 useEffect(() => { const newConfig = (component.webTypeConfig as ButtonTypeConfig) || {}; // 기본값 설정 (실제 값이 있으면 덮어쓰지 않음) const defaultConfig = { actionType: "custom" as ButtonActionType, variant: "default" as ButtonVariant, }; // 실제 저장된 값이 우선순위를 가지도록 설정 setLocalConfig({ ...defaultConfig, ...newConfig, // 저장된 값이 기본값을 덮어씀 }); console.log("🔄 ButtonConfigPanel 로컬 상태 동기화:", { componentId: component.id, savedConfig: newConfig, finalConfig: { ...defaultConfig, ...newConfig }, }); }, [component.webTypeConfig, component.id]); // 설정 업데이트 함수 const updateConfig = (updates: Partial) => { const newConfig = { ...localConfig, ...updates }; setLocalConfig(newConfig); // 스타일 업데이트도 함께 적용 const styleUpdates: any = {}; if (updates.backgroundColor) styleUpdates.backgroundColor = updates.backgroundColor; if (updates.textColor) styleUpdates.color = updates.textColor; if (updates.borderColor) styleUpdates.borderColor = updates.borderColor; onUpdateComponent({ webTypeConfig: newConfig, ...(Object.keys(styleUpdates).length > 0 && { style: { ...component.style, ...styleUpdates }, }), }); }; // 액션 타입 변경 시 기본값 설정 const handleActionTypeChange = (actionType: ButtonActionType) => { const actionOption = actionTypeOptions.find((opt) => opt.value === actionType); const updates: Partial = { actionType }; // 액션 타입에 따른 기본 설정 switch (actionType) { case "save": updates.variant = "default"; updates.backgroundColor = "#3b82f6"; updates.textColor = "#ffffff"; // 버튼 라벨과 스타일도 업데이트 onUpdateComponent({ label: "저장", style: { ...component.style, backgroundColor: "#3b82f6", color: "#ffffff" }, }); break; case "close": updates.variant = "outline"; updates.backgroundColor = "transparent"; updates.textColor = "#6b7280"; onUpdateComponent({ label: "닫기", style: { ...component.style, backgroundColor: "transparent", color: "#6b7280", border: "1px solid #d1d5db" }, }); break; case "delete": updates.variant = "destructive"; updates.backgroundColor = "#ef4444"; updates.textColor = "#ffffff"; updates.confirmMessage = "정말로 삭제하시겠습니까?"; onUpdateComponent({ label: "삭제", style: { ...component.style, backgroundColor: "#ef4444", color: "#ffffff" }, }); break; case "edit": updates.backgroundColor = "#f59e0b"; updates.textColor = "#ffffff"; onUpdateComponent({ label: "수정", style: { ...component.style, backgroundColor: "#f59e0b", color: "#ffffff" }, }); break; case "add": updates.backgroundColor = "#10b981"; updates.textColor = "#ffffff"; onUpdateComponent({ label: "추가", style: { ...component.style, backgroundColor: "#10b981", color: "#ffffff" }, }); break; case "search": updates.backgroundColor = "#8b5cf6"; updates.textColor = "#ffffff"; onUpdateComponent({ label: "검색", style: { ...component.style, backgroundColor: "#8b5cf6", color: "#ffffff" }, }); break; case "reset": updates.variant = "outline"; updates.backgroundColor = "transparent"; updates.textColor = "#6b7280"; onUpdateComponent({ label: "초기화", style: { ...component.style, backgroundColor: "transparent", color: "#6b7280", border: "1px solid #d1d5db" }, }); break; case "submit": updates.backgroundColor = "#059669"; updates.textColor = "#ffffff"; onUpdateComponent({ label: "제출", style: { ...component.style, backgroundColor: "#059669", color: "#ffffff" }, }); break; case "popup": updates.backgroundColor = "#8b5cf6"; updates.textColor = "#ffffff"; updates.popupTitle = "상세 정보"; updates.popupContent = "여기에 모달 내용을 입력하세요."; updates.popupSize = "md"; onUpdateComponent({ label: "상세보기", style: { ...component.style, backgroundColor: "#8b5cf6", color: "#ffffff" }, }); break; case "navigate": updates.backgroundColor = "#0ea5e9"; updates.textColor = "#ffffff"; updates.navigateType = "url"; updates.navigateUrl = "/"; updates.navigateTarget = "_self"; onUpdateComponent({ label: "이동", style: { ...component.style, backgroundColor: "#0ea5e9", color: "#ffffff" }, }); break; case "custom": updates.backgroundColor = "#64748b"; updates.textColor = "#ffffff"; onUpdateComponent({ label: "버튼", style: { ...component.style, backgroundColor: "#64748b", color: "#ffffff" }, }); break; } // 로컬 상태 업데이트 후 webTypeConfig도 함께 업데이트 const newConfig = { ...localConfig, ...updates }; setLocalConfig(newConfig); // webTypeConfig를 마지막에 다시 업데이트하여 확실히 저장되도록 함 setTimeout(() => { onUpdateComponent({ webTypeConfig: newConfig, }); console.log("🎯 ButtonActionType webTypeConfig 최종 업데이트:", { actionType, newConfig, componentId: component.id, }); }, 0); }; const selectedActionOption = actionTypeOptions.find((opt) => opt.value === localConfig.actionType); return (
버튼 기능 설정 {/* 액션 타입 선택 */}
{selectedActionOption && (
{selectedActionOption.icon} {selectedActionOption.label} {selectedActionOption.value}
)}
{/* 기본 설정 */}
{/* 버튼 텍스트 */}
{ const newValue = e.target.value; onUpdateComponent({ label: newValue }); }} placeholder="버튼에 표시될 텍스트" className="h-8 text-xs" />
{/* 버튼 스타일 */}
{/* 아이콘 설정 */}
updateConfig({ icon: e.target.value })} placeholder="예: Save, Edit, Trash2" className="h-8 text-xs" />
{/* 액션별 세부 설정 */} {localConfig.actionType === "delete" && (
updateConfig({ confirmMessage: e.target.value })} placeholder="정말로 삭제하시겠습니까?" className="h-8 text-xs" />
)} {localConfig.actionType === "popup" && (
{localConfig.popupScreenId &&

선택된 화면이 모달로 열립니다

}
updateConfig({ popupTitle: e.target.value })} placeholder="상세 정보" className="h-8 text-xs" />
{!localConfig.popupScreenId && (