"use client"; import React, { useState, useEffect } from "react"; import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card"; import { Button } from "@/components/ui/button"; import { Input } from "@/components/ui/input"; import { Textarea } from "@/components/ui/textarea"; import { Label } from "@/components/ui/label"; import { Mail, Type, Image as ImageIcon, Square, MousePointer, Eye, Send, Save, Plus, Trash2, Settings, Upload, X } from "lucide-react"; import { getMailTemplates } from "@/lib/api/mail"; export interface MailComponent { id: string; type: "text" | "button" | "image" | "spacer" | "table"; content?: string; text?: string; url?: string; src?: string; height?: number; styles?: Record; } export interface QueryConfig { id: string; name: string; sql: string; parameters: Array<{ name: string; type: string; value?: any; }>; } interface MailDesignerProps { templateId?: string; onSave?: (data: any) => void; onPreview?: (data: any) => void; onSend?: (data: any) => void; } export default function MailDesigner({ templateId, onSave, onPreview, onSend, }: MailDesignerProps) { const [components, setComponents] = useState([]); const [selectedComponent, setSelectedComponent] = useState(null); const [templateName, setTemplateName] = useState(""); const [subject, setSubject] = useState(""); const [queries, setQueries] = useState([]); const [isLoading, setIsLoading] = useState(false); // 템플릿 데이터 로드 (수정 모드) useEffect(() => { if (templateId) { loadTemplate(templateId); } }, [templateId]); const loadTemplate = async (id: string) => { try { setIsLoading(true); const templates = await getMailTemplates(); const template = templates.find(t => t.id === id); if (template) { setTemplateName(template.name); setSubject(template.subject); setComponents(template.components || []); console.log('✅ 템플릿 로드 완료:', { name: template.name, components: template.components?.length || 0 }); } } catch (error) { console.error('❌ 템플릿 로드 실패:', error); } finally { setIsLoading(false); } }; // 컴포넌트 타입 정의 const componentTypes = [ { type: "text", icon: Type, label: "텍스트", color: "bg-primary/20 hover:bg-blue-200" }, { type: "button", icon: MousePointer, label: "버튼", color: "bg-success/20 hover:bg-success/30" }, { type: "image", icon: ImageIcon, label: "이미지", color: "bg-purple-100 hover:bg-purple-200" }, { type: "spacer", icon: Square, label: "여백", color: "bg-muted hover:bg-muted/80" }, ]; // 컴포넌트 추가 const addComponent = (type: string) => { const newComponent: MailComponent = { id: `comp-${Date.now()}`, type: type as any, content: type === "text" ? "" : undefined, // 🎯 빈 문자열로 시작 (HTML 태그 제거) text: type === "button" ? "버튼 텍스트" : undefined, // 🎯 더 명확한 기본값 url: type === "button" || type === "image" ? "" : undefined, // 🎯 빈 문자열로 시작 src: type === "image" ? "https://placehold.co/600x200/e5e7eb/64748b?text=이미지를+업로드하세요" : undefined, // 🎯 한글 안내 height: type === "spacer" ? 30 : undefined, // 🎯 기본값 30px로 증가 (더 적절한 간격) styles: { padding: "10px", backgroundColor: type === "button" ? "#007bff" : "transparent", color: type === "button" ? "#fff" : "#333", }, }; setComponents([...components, newComponent]); }; // 컴포넌트 삭제 const removeComponent = (id: string) => { setComponents(components.filter(c => c.id !== id)); if (selectedComponent === id) { setSelectedComponent(null); } }; // 컴포넌트 선택 const selectComponent = (id: string) => { setSelectedComponent(id); }; // 컴포넌트 내용 업데이트 const updateComponent = (id: string, updates: Partial) => { setComponents( components.map(c => c.id === id ? { ...c, ...updates } : c) ); }; // 저장 const handleSave = () => { const data = { name: templateName, subject, components, queries, }; if (onSave) { onSave(data); } }; // 미리보기 const handlePreview = () => { if (onPreview) { onPreview({ components, subject }); } }; // 발송 const handleSend = () => { if (onSend) { onSend({ components, subject, queries }); } }; // 선택된 컴포넌트 가져오기 const selected = components.find(c => c.id === selectedComponent); // 로딩 중일 때 if (isLoading) { return (

템플릿을 불러오는 중...

); } return (
{/* 왼쪽: 컴포넌트 팔레트 */}

컴포넌트

{componentTypes.map(({ type, icon: Icon, label, color }) => ( ))}
{/* 템플릿 정보 */} 템플릿 정보
setTemplateName(e.target.value)} placeholder="예: 고객 환영 메일" className="mt-1" />
setSubject(e.target.value)} placeholder="예: {customer_name}님 환영합니다!" className="mt-1" />
{/* 액션 버튼 */}
{/* 중앙: 캔버스 */}
메일 미리보기 {components.length}개 컴포넌트 {/* 제목 영역 */} {subject && (

제목:

{subject}

)} {/* 컴포넌트 렌더링 */}
{components.length === 0 ? (

왼쪽에서 컴포넌트를 추가하세요

) : ( components.map((comp) => (
selectComponent(comp.id)} className={`relative group cursor-pointer rounded-lg transition-all ${ selectedComponent === comp.id ? "ring-2 ring-orange-500 bg-orange-50/30" : "hover:ring-2 hover:ring-gray-300" }`} style={comp.styles} > {/* 삭제 버튼 */} {/* 컴포넌트 내용 */} {comp.type === "text" && (
)} {comp.type === "button" && ( {comp.text} )} {comp.type === "image" && ( 메일 이미지 )} {comp.type === "spacer" && (
)}
)) )}
{/* 오른쪽: 속성 패널 */}
{selected ? (

속성 편집

{/* 텍스트 컴포넌트 */} {selected.type === "text" && (

메일에 표시될 텍스트를 입력하세요