From fb20768fa881841d3f80d12a276a9445feb6f514 Mon Sep 17 00:00:00 2001
From: joonhoekim <26rote@gmail.com>
Date: Tue, 30 Sep 2025 05:04:33 +0000
Subject: (고건) 이메일 템플릿 정보 수정/복제 기능 에러 수정
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 lib/email-template/editor/template-settings.tsx | 205 ++++++++++++------------
 1 file changed, 100 insertions(+), 105 deletions(-)

(limited to 'lib/email-template/editor/template-settings.tsx')

diff --git a/lib/email-template/editor/template-settings.tsx b/lib/email-template/editor/template-settings.tsx
index f253f87d..99ef5443 100644
--- a/lib/email-template/editor/template-settings.tsx
+++ b/lib/email-template/editor/template-settings.tsx
@@ -1,24 +1,6 @@
-"use client"
+'use client';
 
-import * as React from "react"
-import { Button } from "@/components/ui/button"
-import { Input } from "@/components/ui/input"
-import { Label } from "@/components/ui/label"
-import { Textarea } from "@/components/ui/textarea"
-import {
-  Select,
-  SelectContent,
-  SelectItem,
-  SelectTrigger,
-  SelectValue,
-} from "@/components/ui/select"
-import {
-  Card,
-  CardContent,
-  CardDescription,
-  CardHeader,
-  CardTitle,
-} from "@/components/ui/card"
+/* IMPORT */
 import {
   AlertDialog,
   AlertDialogAction,
@@ -29,68 +11,92 @@ import {
   AlertDialogHeader,
   AlertDialogTitle,
   AlertDialogTrigger,
-} from "@/components/ui/alert-dialog"
-import { Badge } from "@/components/ui/badge"
-import { Separator } from "@/components/ui/separator"
+} from '@/components/ui/alert-dialog';
 import { 
-  Save, 
-  Trash2, 
   AlertTriangle, 
-  Info, 
   Calendar,
-  User,
+  Copy,
   Hash,
-  Copy
-} from "lucide-react"
-import { toast } from "sonner"
-import { useRouter } from "next/navigation"
-import { type TemplateWithVariables } from "@/db/schema"
-import { deleteTemplate, duplicateTemplate, updateTemplateAction } from "../service"
-import { TEMPLATE_CATEGORY_OPTIONS, getCategoryDisplayName } from "../validations"
+  Info,
+  Save,
+  Trash2,
+  User,
+} from 'lucide-react';
+import { Badge } from '@/components/ui/badge';
+import { Button } from '@/components/ui/button';
+import {
+  Card,
+  CardContent,
+  CardDescription,
+  CardHeader,
+  CardTitle,
+} from '@/components/ui/card';
+import { deleteTemplate, duplicateTemplate, getCurrentUserId, updateTemplateAction } from '../service';
+import { getCategoryDisplayName, TEMPLATE_CATEGORY_OPTIONS } from '../validations';
+import { Input } from '@/components/ui/input';
+import { Label } from '@/components/ui/label';
+import {
+  Select,
+  SelectContent,
+  SelectItem,
+  SelectTrigger,
+  SelectValue,
+} from '@/components/ui/select';
+import { Separator } from '@/components/ui/separator';
+import { Textarea } from '@/components/ui/textarea';
+import { toast } from 'sonner';
+import { type TemplateWithVariables } from '@/db/schema';
+import { useRouter } from 'next/navigation';
+import { useState } from 'react';
 
+// ----------------------------------------------------------------------------------------------------
 
+/* TYPES */
 interface TemplateSettingsProps {
-  template: TemplateWithVariables
-  onUpdate: (template: TemplateWithVariables) => void
+  template: TemplateWithVariables;
+  onUpdate: (template: TemplateWithVariables) => void;
 }
 
+// ----------------------------------------------------------------------------------------------------
+
 export function TemplateSettings({ template, onUpdate }: TemplateSettingsProps) {
-  const router = useRouter()
-  const [isLoading, setIsLoading] = React.useState(false)
-  const [formData, setFormData] = React.useState({
+  const router = useRouter();
+  const [isLoading, setIsLoading] = useState(false);
+  const [formData, setFormData] = useState({
     name: template.name,
     description: template.description || '',
     category: template.category || '',
     sampleData: JSON.stringify(template.sampleData || {}, null, 2)
-  })
+  });
 
   // 폼 데이터 업데이트
   const updateFormData = (field: keyof typeof formData, value: string) => {
     setFormData(prev => ({ ...prev, [field]: value }))
-  }
+  };
 
   // 기본 정보 저장
   const handleSaveBasicInfo = async () => {
-    setIsLoading(true)
+    setIsLoading(true);
     try {
       // 샘플 데이터 JSON 파싱 검증
-      let parsedSampleData = {}
+      let parsedSampleData = {};
       if (formData.sampleData.trim()) {
         try {
-          parsedSampleData = JSON.parse(formData.sampleData)
+          parsedSampleData = JSON.parse(formData.sampleData);
         } catch (error) {
-          toast.error('샘플 데이터 JSON 형식이 올바르지 않습니다.')
-          setIsLoading(false)
-          return
+          toast.error('샘플 데이터 JSON 형식이 올바르지 않습니다.');
+          setIsLoading(false);
+          return;
         }
       }
 
       const result = await updateTemplateAction(template.slug, {
         name: formData.name,
         description: formData.description || undefined,
+        category: formData.category,
         sampleData: parsedSampleData,
-        updatedBy: 'current-user-id' // TODO: 실제 사용자 ID
-      })
+        updatedBy: await getCurrentUserId(),
+      });
 
       if (result.success) {
         toast.success('템플릿 설정이 저장되었습니다.')
@@ -98,62 +104,63 @@ export function TemplateSettings({ template, onUpdate }: TemplateSettingsProps)
           ...template,
           name: formData.name,
           description: formData.description,
+          category: formData.category,
           sampleData: parsedSampleData,
-          version: template.version + 1
-        })
+          version: template.version ? template.version + 1 : 1,
+        });
       } else {
-        toast.error(result.error || '저장에 실패했습니다.')
+        toast.error(result.error || '저장에 실패했습니다.');
       }
     } catch (error) {
-      toast.error('저장 중 오류가 발생했습니다.')
+      toast.error('저장 중 오류가 발생했습니다.');
     } finally {
-      setIsLoading(false)
+      setIsLoading(false);
     }
   }
 
   // 템플릿 복제
   const handleDuplicate = async () => {
-    setIsLoading(true)
+    setIsLoading(true);
     try {
-      const copyName = `${template.name} (복사본)`
-      const copySlug = `${template.slug}-copy-${Date.now()}`
+      const copyName = `${template.name} (복사본)`;
+      const copySlug = `${template.slug}-copy-${Date.now()}`;
       
       const result = await duplicateTemplate(
         template.id,
         copyName,
         copySlug,
-        'current-user-id' // TODO: 실제 사용자 ID
-      )
+        await getCurrentUserId(),
+      );
 
       if (result.success && result.data) {
-        toast.success('템플릿이 복제되었습니다.')
-        router.push(`/evcp/templates/${result.data.slug}`)
+        toast.success('템플릿이 복제되었습니다.');
+        router.push(`/evcp/email-template/${result.data.slug}`);
       } else {
-        toast.error(result.error || '복제에 실패했습니다.')
+        toast.error(result.error || '복제에 실패했습니다.');
       }
     } catch (error) {
-      toast.error('복제 중 오류가 발생했습니다.')
+      toast.error('복제 중 오류가 발생했습니다.');
     } finally {
-      setIsLoading(false)
+      setIsLoading(false);
     }
   }
 
   // 템플릿 삭제
   const handleDelete = async () => {
-    setIsLoading(true)
+    setIsLoading(true);
     try {
-      const result = await deleteTemplate(template.id)
+      const result = await deleteTemplate(template.id);
 
       if (result.success) {
-        toast.success('템플릿이 삭제되었습니다.')
-        router.push('/evcp/templates')
+        toast.success('템플릿이 삭제되었습니다.');
+        router.push('/evcp/email-template');
       } else {
-        toast.error(result.error || '삭제에 실패했습니다.')
+        toast.error(result.error || '삭제에 실패했습니다.');
       }
     } catch (error) {
-      toast.error('삭제 중 오류가 발생했습니다.')
+      toast.error('삭제 중 오류가 발생했습니다.');
     } finally {
-      setIsLoading(false)
+      setIsLoading(false);
     }
   }
 
@@ -215,7 +222,6 @@ export function TemplateSettings({ template, onUpdate }: TemplateSettingsProps)
               placeholder="템플릿 이름을 입력하세요"
             />
           </div>
-
           <div>
             <Label htmlFor="description">설명</Label>
             <Textarea
@@ -226,30 +232,28 @@ export function TemplateSettings({ template, onUpdate }: TemplateSettingsProps)
               className="min-h-[100px]"
             />
           </div>
-
           <div>
-  <Label htmlFor="category">카테고리</Label>
-  <Select
-    value={formData.category || "none"} // 빈 문자열일 때 "none"으로 표시
-    onValueChange={(value) => {
-      // "none"이 선택되면 빈 문자열로 변환
-      updateFormData('category', value === "none" ? "" : value)
-    }}
-  >
-    <SelectTrigger>
-      <SelectValue placeholder="카테고리를 선택하세요" />
-    </SelectTrigger>
-    <SelectContent>
-      <SelectItem value="none">카테고리 없음</SelectItem> {/* ✅ "none" 사용 */}
-      {TEMPLATE_CATEGORY_OPTIONS.map((option) => (
-        <SelectItem key={option.value} value={option.value}>
-          {option.label}
-        </SelectItem>
-      ))}
-    </SelectContent>
-  </Select>
-</div>
-
+            <Label htmlFor="category">카테고리</Label>
+            <Select
+              value={formData.category || "none"} // 빈 문자열일 때 "none"으로 표시
+              onValueChange={(value) => {
+                // "none"이 선택되면 빈 문자열로 변환
+                updateFormData('category', value === "none" ? "" : value)
+              }}
+            >
+              <SelectTrigger>
+                <SelectValue placeholder="카테고리를 선택하세요" />
+              </SelectTrigger>
+              <SelectContent>
+                <SelectItem value="none">카테고리 없음</SelectItem> {/* ✅ "none" 사용 */}
+                {TEMPLATE_CATEGORY_OPTIONS.map((option) => (
+                  <SelectItem key={option.value} value={option.value}>
+                    {option.label}
+                  </SelectItem>
+                ))}
+              </SelectContent>
+            </Select>
+          </div>
           <div className="flex justify-end">
             <Button onClick={handleSaveBasicInfo} disabled={isLoading}>
               <Save className="mr-2 h-4 w-4" />
@@ -284,7 +288,6 @@ export function TemplateSettings({ template, onUpdate }: TemplateSettingsProps)
               기본 데이터 생성
             </Button>
           </div>
-
           <div>
             <Label htmlFor="sampleData">샘플 데이터 (JSON)</Label>
             <Textarea
@@ -295,7 +298,6 @@ export function TemplateSettings({ template, onUpdate }: TemplateSettingsProps)
               className="min-h-[200px] font-mono text-sm"
             />
           </div>
-
           <div className="bg-blue-50 p-3 rounded-lg">
             <p className="text-sm text-blue-800">
               <Info className="inline h-4 w-4 mr-1" />
@@ -323,21 +325,18 @@ export function TemplateSettings({ template, onUpdate }: TemplateSettingsProps)
                   {template.slug}
                 </code>
               </div>
-
               <div className="flex items-center gap-2">
                 <Badge variant="outline">버전 {template.version}</Badge>
                 <Badge variant={template.category ? "default" : "secondary"}>
                   {getCategoryDisplayName(template.category)}
                 </Badge>
               </div>
-
               <div className="flex items-center gap-2">
                 <Calendar className="h-4 w-4 text-muted-foreground" />
                 <span className="text-sm">
                   생성일: {new Date(template.createdAt).toLocaleString('ko-KR')}
                 </span>
               </div>
-
               <div className="flex items-center gap-2">
                 <Calendar className="h-4 w-4 text-muted-foreground" />
                 <span className="text-sm">
@@ -345,7 +344,6 @@ export function TemplateSettings({ template, onUpdate }: TemplateSettingsProps)
                 </span>
               </div>
             </div>
-
             <div className="space-y-3">
               <div className="flex items-center gap-2">
                 <User className="h-4 w-4 text-muted-foreground" />
@@ -353,19 +351,16 @@ export function TemplateSettings({ template, onUpdate }: TemplateSettingsProps)
                   생성자: {template.createdBy}
                 </span>
               </div>
-
               <div>
                 <span className="text-sm font-medium">변수 개수:</span>
                 <span className="ml-2 text-sm">{template.variables.length}개</span>
               </div>
-
               <div>
                 <span className="text-sm font-medium">필수 변수:</span>
                 <span className="ml-2 text-sm">
                   {template.variables.filter(v => v.isRequired).length}개
                 </span>
               </div>
-
               <div>
                 <span className="text-sm font-medium">콘텐츠 길이:</span>
                 <span className="ml-2 text-sm">{template.content.length} 문자</span>
@@ -471,4 +466,4 @@ export function TemplateSettings({ template, onUpdate }: TemplateSettingsProps)
       </div>
     </div>
   )
-}
\ No newline at end of file
+}
-- 
cgit v1.2.3

