"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 { Label } from "@/components/ui/label"; import { Badge } from "@/components/ui/badge"; import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue, } from "@/components/ui/select"; import { Inbox, Search, Filter, Eye, Trash2, RefreshCw, CheckCircle2, XCircle, Mail, Calendar, User, Paperclip, Loader2, X, File, ChevronRight, ChevronDown, ChevronUp, Send, AlertCircle, } from "lucide-react"; import { useRouter } from "next/navigation"; import Link from "next/link"; import { Separator } from "@/components/ui/separator"; import { Dialog, DialogContent, DialogHeader, DialogTitle, } from "@/components/ui/dialog"; import { SentMailHistory, getSentMailList, deleteSentMail, getMailAccounts, MailAccount, getMailStatistics, } from "@/lib/api/mail"; import { useToast } from "@/hooks/use-toast"; export default function SentMailPage() { const router = useRouter(); const { toast } = useToast(); const [mails, setMails] = useState([]); const [accounts, setAccounts] = useState([]); const [loading, setLoading] = useState(false); const [selectedMail, setSelectedMail] = useState(null); const [showFilters, setShowFilters] = useState(false); // 통계 const [stats, setStats] = useState({ totalSent: 0, successCount: 0, failedCount: 0, todayCount: 0, }); // 필터 및 페이징 const [searchTerm, setSearchTerm] = useState(""); const [filterStatus, setFilterStatus] = useState<'all' | 'success' | 'failed'>('all'); const [filterAccountId, setFilterAccountId] = useState('all'); const [sortBy, setSortBy] = useState<'sentAt' | 'subject'>('sentAt'); const [sortOrder, setSortOrder] = useState<'asc' | 'desc'>('desc'); const [page, setPage] = useState(1); const [totalPages, setTotalPages] = useState(1); const [total, setTotal] = useState(0); useEffect(() => { loadAccounts(); loadStats(); }, []); useEffect(() => { loadMails(); }, [page, filterStatus, filterAccountId, sortBy, sortOrder]); const loadAccounts = async () => { try { const data = await getMailAccounts(); setAccounts(data); } catch (error: unknown) { const err = error as Error; toast({ title: "계정 로드 실패", description: err.message, variant: "destructive", }); } }; const loadStats = async () => { try { const data = await getMailStatistics(); setStats({ totalSent: data.totalSent, successCount: data.successCount, failedCount: data.failedCount, todayCount: data.todayCount, }); } catch (error: unknown) { console.error('통계 로드 실패:', error); } }; const loadMails = async () => { try { setLoading(true); const result = await getSentMailList({ page, limit: 20, searchTerm: searchTerm || undefined, status: filterStatus, accountId: filterAccountId !== 'all' ? filterAccountId : undefined, sortBy, sortOrder, }); setMails(result.items); setTotalPages(result.totalPages); setTotal(result.total); } catch (error: unknown) { const err = error as Error; toast({ title: "발송 이력 로드 실패", description: err.message, variant: "destructive", }); } finally { setLoading(false); } }; const handleSearch = () => { setPage(1); loadMails(); }; const handleDelete = async (id: string) => { if (!confirm("이 발송 이력을 삭제하시겠습니까?")) { return; } try { await deleteSentMail(id); toast({ title: "삭제 완료", description: "발송 이력이 삭제되었습니다.", }); loadMails(); loadStats(); } catch (error: unknown) { const err = error as Error; toast({ title: "삭제 실패", description: err.message, variant: "destructive", }); } }; const formatDate = (dateString: string) => { const date = new Date(dateString); return date.toLocaleString('ko-KR', { year: 'numeric', month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit', }); }; const formatFileSize = (bytes: number) => { if (bytes === 0) return "0 Bytes"; const k = 1024; const sizes = ["Bytes", "KB", "MB"]; const i = Math.floor(Math.log(bytes) / Math.log(k)); return Math.round(bytes / Math.pow(k, i) * 100) / 100 + " " + sizes[i]; }; if (loading && page === 1 && mails.length === 0) { return (
); } return (
{/* 헤더 */}
{/* 브레드크럼브 */} {/* 제목 및 빠른 액션 */}

보낸메일함

총 {total}개의 발송 이력

{/* 통계 카드 */}

전체 발송

{stats.totalSent}

발송 성공

{stats.successCount}

발송 실패

{stats.failedCount}

오늘 발송

{stats.todayCount}

{/* 검색 및 필터 */}
검색
{/* 기본 검색 */}
setSearchTerm(e.target.value)} onKeyDown={(e) => e.key === 'Enter' && handleSearch()} placeholder="제목 또는 받는사람으로 검색..." className="flex-1" />
{/* 고급 필터 (접기/펼치기) */} {showFilters && (
{/* 상태 필터 */}
{/* 계정 필터 */}
{/* 정렬 */}
{/* 필터 초기화 */}
)}
{/* 메일 목록 */} 발송 이력 ({total}건) {loading ? (
) : mails.length === 0 ? (

발송 이력이 없습니다

) : (
{mails.map((mail) => (
{/* 메일 정보 */}
{/* 상태 배지 */} {mail.status === 'success' ? ( 발송 성공 ) : ( 발송 실패 )} {/* 첨부파일 */} {mail.attachmentCount > 0 && ( {mail.attachmentCount}개 )}
{/* 제목 */}

{mail.subject || "(제목 없음)"}

{/* 수신자 및 날짜 */}
{Array.isArray(mail.to) ? mail.to.join(", ") : mail.to} {formatDate(mail.sentAt)}
{/* 실패 메시지 */} {mail.status === 'failed' && mail.errorMessage && (
{mail.errorMessage}
)}
{/* 액션 버튼 */}
))}
)} {/* 페이징 */} {totalPages > 1 && (

페이지 {page} / {totalPages}

)}
{/* 메일 상세 모달 */} {selectedMail && ( setSelectedMail(null)}> 발송 상세정보
{/* 상태 */}
{selectedMail.status === 'success' ? ( 발송 성공 ) : ( 발송 실패 )} {selectedMail.status === 'failed' && selectedMail.errorMessage && (

{selectedMail.errorMessage}

)}
{/* 발신 정보 */}

발신 정보

보낸사람: {selectedMail.from}
받는사람: {Array.isArray(selectedMail.to) ? selectedMail.to.join(", ") : selectedMail.to}
{selectedMail.cc && selectedMail.cc.length > 0 && (
참조: {selectedMail.cc.join(", ")}
)} {selectedMail.bcc && selectedMail.bcc.length > 0 && (
숨은참조: {selectedMail.bcc.join(", ")}
)}
발송일시: {formatDate(selectedMail.sentAt)}
{/* 메일 내용 */}

메일 내용

제목

{selectedMail.subject || "(제목 없음)"}

{selectedMail.templateUsed && (

사용 템플릿

{selectedMail.templateUsed}
)}

본문

{/* 첨부파일 */} {selectedMail.attachments && selectedMail.attachments.length > 0 && ( <>

첨부파일 ({selectedMail.attachments.length}개)

{selectedMail.attachments.map((att, idx) => (

{att.filename}

{formatFileSize(att.size || 0)}

))}
)} {/* 수신 결과 (성공/실패 목록) */} {selectedMail.acceptedRecipients && selectedMail.acceptedRecipients.length > 0 && ( <>

수신 성공

{selectedMail.acceptedRecipients.map((email, idx) => ( {email} ))}
)} {selectedMail.rejectedRecipients && selectedMail.rejectedRecipients.length > 0 && ( <>

수신 실패

{selectedMail.rejectedRecipients.map((email, idx) => ( {email} ))}
)}
)}
); }