From e9897d416b3e7327bbd4d4aef887eee37751ae82 Mon Sep 17 00:00:00 2001
From: dujinkim <dujin.kim@dtsolution.co.kr>
Date: Fri, 27 Jun 2025 01:16:20 +0000
Subject: (대표님) 20250627 오전 10시 작업사항
MIME-Version: 1.0
Content-Type: text/plain; charset=UTF-8
Content-Transfer-Encoding: 8bit

---
 components/mail/mail-templates-client.tsx | 218 ++++++++++++++++++++++++++++++
 1 file changed, 218 insertions(+)
 create mode 100644 components/mail/mail-templates-client.tsx

(limited to 'components/mail/mail-templates-client.tsx')

diff --git a/components/mail/mail-templates-client.tsx b/components/mail/mail-templates-client.tsx
new file mode 100644
index 00000000..7c4dafdf
--- /dev/null
+++ b/components/mail/mail-templates-client.tsx
@@ -0,0 +1,218 @@
+'use client';
+
+import { useState, useEffect, useTransition } from 'react';
+import Link from 'next/link';
+import { useParams } from 'next/navigation';
+import { Button } from '@/components/ui/button';
+import { Input } from '@/components/ui/input';
+import {
+  Table,
+  TableBody,
+  TableCell,
+  TableHead,
+  TableHeader,
+  TableRow,
+} from '@/components/ui/table';
+import { Search, Edit, FileText, ChevronUp, ChevronDown } from 'lucide-react';
+import { toast } from 'sonner';
+import { getTemplatesAction, TemplateFile } from '@/lib/mail/service';
+
+type Template = TemplateFile;
+
+interface MailTemplatesClientProps {
+  initialData?: Template[];
+}
+
+type SortField = 'name' | 'lastModified';
+type SortDirection = 'asc' | 'desc';
+
+export default function MailTemplatesClient({ initialData = [] }: MailTemplatesClientProps) {
+  const params = useParams();
+  const lng = (params?.lng as string) || 'ko';
+  
+  const [templates, setTemplates] = useState<Template[]>(initialData);
+  const [loading, setLoading] = useState(false);
+  const [searchQuery, setSearchQuery] = useState('');
+  const [sortField, setSortField] = useState<SortField>('name');
+  const [sortDirection, setSortDirection] = useState<SortDirection>('asc');
+  const [, startTransition] = useTransition();
+
+  // 템플릿 목록 조회
+  const fetchTemplates = async () => {
+    try {
+      setLoading(true);
+      const search = searchQuery || undefined;
+
+      startTransition(async () => {
+        const result = await getTemplatesAction(search);
+
+        if (result.success && result.data) {
+          setTemplates(result.data);
+        } else {
+          toast.error(result.error || '템플릿 목록을 가져오는데 실패했습니다.');
+        }
+        setLoading(false);
+      });
+    } catch (error) {
+      console.error('Error fetching templates:', error);
+      toast.error('템플릿 목록을 가져오는데 실패했습니다.');
+      setLoading(false);
+    }
+  };
+
+  // 검색 핸들러
+  const handleSearch = () => {
+    fetchTemplates();
+  };
+
+  // 정렬 함수
+  const sortTemplates = (templates: Template[]) => {
+    return [...templates].sort((a, b) => {
+      let aValue: string | Date;
+      let bValue: string | Date;
+
+      if (sortField === 'name') {
+        aValue = a.name;
+        bValue = b.name;
+      } else {
+        aValue = new Date(a.lastModified);
+        bValue = new Date(b.lastModified);
+      }
+
+      if (aValue < bValue) {
+        return sortDirection === 'asc' ? -1 : 1;
+      }
+      if (aValue > bValue) {
+        return sortDirection === 'asc' ? 1 : -1;
+      }
+      return 0;
+    });
+  };
+
+  // 정렬 핸들러
+  const handleSort = (field: SortField) => {
+    if (sortField === field) {
+      setSortDirection(sortDirection === 'asc' ? 'desc' : 'asc');
+    } else {
+      setSortField(field);
+      setSortDirection('asc');
+    }
+  };
+
+  // 정렬된 템플릿 목록
+  const sortedTemplates = sortTemplates(templates);
+
+  useEffect(() => {
+    if (searchQuery !== '') {
+      fetchTemplates();
+    } else {
+      setTemplates(initialData);
+    }
+  }, [searchQuery, initialData]);
+
+  return (
+    <div className="space-y-6">
+      {/* 검색 */}
+      <div className="flex items-center gap-4">
+        <div className="relative flex-1 max-w-md">
+          <Search className="absolute left-3 top-1/2 transform -translate-y-1/2 text-gray-400 h-4 w-4" />
+          <Input
+            placeholder="템플릿 이름 또는 내용으로 검색..."
+            value={searchQuery}
+            onChange={(e) => setSearchQuery(e.target.value)}
+            className="pl-10"
+            onKeyPress={(e) => e.key === 'Enter' && handleSearch()}
+          />
+        </div>
+        <Button onClick={handleSearch} variant="outline">
+          검색
+        </Button>
+        <Button
+          variant="outline"
+          onClick={() => window.location.reload()}
+        >
+          새로고침
+        </Button>
+      </div>
+
+      {/* 템플릿 테이블 */}
+      <div className="bg-white rounded-lg shadow">
+        <Table>
+          <TableHeader>
+            <TableRow>
+              <TableHead>
+                <button
+                  className="flex items-center gap-1 hover:text-foreground"
+                  onClick={() => handleSort('name')}
+                >
+                  이름
+                  {sortField === 'name' && (
+                    sortDirection === 'asc' ? (
+                      <ChevronUp className="h-4 w-4" />
+                    ) : (
+                      <ChevronDown className="h-4 w-4" />
+                    )
+                  )}
+                </button>
+              </TableHead>
+              <TableHead>
+                <button
+                  className="flex items-center gap-1 hover:text-foreground"
+                  onClick={() => handleSort('lastModified')}
+                >
+                  수정일
+                  {sortField === 'lastModified' && (
+                    sortDirection === 'asc' ? (
+                      <ChevronUp className="h-4 w-4" />
+                    ) : (
+                      <ChevronDown className="h-4 w-4" />
+                    )
+                  )}
+                </button>
+              </TableHead>
+              <TableHead className="text-right">작업</TableHead>
+            </TableRow>
+          </TableHeader>
+          <TableBody>
+            {loading ? (
+              <TableRow>
+                <TableCell colSpan={3} className="text-center py-8">
+                  로딩 중...
+                </TableCell>
+              </TableRow>
+            ) : templates.length === 0 ? (
+              <TableRow>
+                <TableCell colSpan={3} className="text-center py-8 text-gray-500">
+                  템플릿이 없습니다.
+                </TableCell>
+              </TableRow>
+            ) : (
+              sortedTemplates.map((template) => (
+                <TableRow key={template.name}>
+                  <TableCell className="font-medium">
+                    <div className="flex items-center gap-2">
+                      <FileText className="h-4 w-4" />
+                      {template.name}
+                    </div>
+                  </TableCell>
+                  <TableCell>
+                    {new Date(template.lastModified).toLocaleString('ko-KR')}
+                  </TableCell>
+                  <TableCell className="text-right">
+                    <div className="flex justify-end gap-2">
+                      <Link href={`/${lng}/evcp/email-template/${template.name}`}>
+                        <Button variant="outline" size="sm">
+                          <Edit className="h-4 w-4" />
+                        </Button>
+                      </Link>
+                    </div>
+                  </TableCell>
+                </TableRow>
+              ))
+            )}
+          </TableBody>
+        </Table>
+      </div>
+    </div>
+  );
+} 
\ No newline at end of file
-- 
cgit v1.2.3

