ERP-node/frontend/app/(main)/admin/automaticMng/mail/accounts/page.tsx

236 lines
8.1 KiB
TypeScript
Raw Normal View History

2025-10-01 16:15:53 +09:00
"use client";
import React, { useState, useEffect } from "react";
import { Card, CardContent, CardHeader, CardTitle } from "@/components/ui/card";
import { Button } from "@/components/ui/button";
2025-10-13 15:17:34 +09:00
import { Mail, Plus, Loader2, RefreshCw, ChevronRight } from "lucide-react";
import { useRouter } from "next/navigation";
2025-10-13 15:17:34 +09:00
import Link from "next/link";
import { Separator } from "@/components/ui/separator";
2025-10-01 16:15:53 +09:00
import {
MailAccount,
getMailAccounts,
createMailAccount,
updateMailAccount,
deleteMailAccount,
2025-10-02 15:46:23 +09:00
testMailAccountConnection,
2025-10-01 16:15:53 +09:00
CreateMailAccountDto,
UpdateMailAccountDto,
} from "@/lib/api/mail";
import MailAccountModal from "@/components/mail/MailAccountModal";
import MailAccountTable from "@/components/mail/MailAccountTable";
import ConfirmDeleteModal from "@/components/mail/ConfirmDeleteModal";
export default function MailAccountsPage() {
const router = useRouter();
2025-10-01 16:15:53 +09:00
const [accounts, setAccounts] = useState<MailAccount[]>([]);
const [loading, setLoading] = useState(false);
const [isModalOpen, setIsModalOpen] = useState(false);
const [isDeleteModalOpen, setIsDeleteModalOpen] = useState(false);
const [selectedAccount, setSelectedAccount] = useState<MailAccount | null>(null);
const [modalMode, setModalMode] = useState<"create" | "edit">("create");
2025-10-01 16:15:53 +09:00
const loadAccounts = async () => {
setLoading(true);
try {
const data = await getMailAccounts();
// 배열인지 확인하고 설정
if (Array.isArray(data)) {
setAccounts(data);
} else {
2025-10-22 17:07:38 +09:00
// console.error('API 응답이 배열이 아닙니다:', data);
2025-10-01 16:15:53 +09:00
setAccounts([]);
}
} catch (error) {
2025-10-22 17:07:38 +09:00
// console.error('계정 로드 실패:', error);
2025-10-01 16:15:53 +09:00
setAccounts([]); // 에러 시 빈 배열로 설정
// alert('계정 목록을 불러오는데 실패했습니다.');
} finally {
setLoading(false);
}
};
useEffect(() => {
loadAccounts();
}, []);
const handleOpenCreateModal = () => {
setModalMode("create");
2025-10-01 16:15:53 +09:00
setSelectedAccount(null);
setIsModalOpen(true);
};
const handleOpenEditModal = (account: MailAccount) => {
setModalMode("edit");
2025-10-01 16:15:53 +09:00
setSelectedAccount(account);
setIsModalOpen(true);
};
const handleOpenDeleteModal = (account: MailAccount) => {
setSelectedAccount(account);
setIsDeleteModalOpen(true);
};
const handleSaveAccount = async (data: CreateMailAccountDto | UpdateMailAccountDto) => {
try {
if (modalMode === "create") {
2025-10-01 16:15:53 +09:00
await createMailAccount(data as CreateMailAccountDto);
} else if (modalMode === "edit" && selectedAccount) {
2025-10-01 16:15:53 +09:00
await updateMailAccount(selectedAccount.id, data as UpdateMailAccountDto);
}
await loadAccounts();
setIsModalOpen(false);
} catch (error) {
throw error; // 모달에서 에러 처리
}
};
const handleDeleteAccount = async () => {
if (!selectedAccount) return;
try {
await deleteMailAccount(selectedAccount.id);
await loadAccounts();
alert("계정이 삭제되었습니다.");
2025-10-01 16:15:53 +09:00
} catch (error) {
2025-10-22 17:07:38 +09:00
// console.error('계정 삭제 실패:', error);
alert("계정 삭제에 실패했습니다.");
2025-10-01 16:15:53 +09:00
}
};
const handleToggleStatus = async (account: MailAccount) => {
try {
const newStatus = account.status === "active" ? "inactive" : "active";
2025-10-01 16:15:53 +09:00
await updateMailAccount(account.id, { status: newStatus });
await loadAccounts();
} catch (error) {
2025-10-22 17:07:38 +09:00
// console.error('상태 변경 실패:', error);
alert("상태 변경에 실패했습니다.");
2025-10-01 16:15:53 +09:00
}
};
2025-10-02 15:46:23 +09:00
const handleTestConnection = async (account: MailAccount) => {
try {
setLoading(true);
const result = await testMailAccountConnection(account.id);
2025-10-02 15:46:23 +09:00
if (result.success) {
alert(`✅ SMTP 연결 성공!\n\n${result.message || "정상적으로 연결되었습니다."}`);
2025-10-02 15:46:23 +09:00
} else {
alert(`❌ SMTP 연결 실패\n\n${result.message || "연결에 실패했습니다."}`);
2025-10-02 15:46:23 +09:00
}
} catch (error: any) {
2025-10-22 17:07:38 +09:00
// console.error('연결 테스트 실패:', error);
alert(`❌ SMTP 연결 테스트 실패\n\n${error.message || "알 수 없는 오류가 발생했습니다."}`);
2025-10-02 15:46:23 +09:00
} finally {
setLoading(false);
}
};
2025-10-01 16:15:53 +09:00
return (
<div className="bg-background min-h-screen">
<div className="w-full max-w-none space-y-8 px-4 py-8">
2025-10-01 16:15:53 +09:00
{/* 페이지 제목 */}
<div className="bg-card space-y-4 rounded-lg border p-6">
2025-10-13 15:17:34 +09:00
{/* 브레드크럼브 */}
<nav className="flex items-center gap-2 text-sm">
<Link
2025-10-13 15:17:34 +09:00
href="/admin/mail/dashboard"
className="text-muted-foreground hover:text-foreground transition-colors"
2025-10-01 16:15:53 +09:00
>
2025-10-13 15:17:34 +09:00
</Link>
<ChevronRight className="text-muted-foreground h-4 w-4" />
2025-10-13 15:17:34 +09:00
<span className="text-foreground font-medium"> </span>
</nav>
2025-10-13 15:17:34 +09:00
<Separator />
2025-10-13 15:17:34 +09:00
{/* 제목 + 액션 버튼들 */}
<div className="flex items-center justify-between">
<div>
<h1 className="text-foreground text-3xl font-bold"> </h1>
<p className="text-muted-foreground mt-2">SMTP </p>
2025-10-13 15:17:34 +09:00
</div>
<div className="flex gap-2">
<Button variant="outline" size="sm" onClick={loadAccounts} disabled={loading}>
<RefreshCw className={`mr-2 h-4 w-4 ${loading ? "animate-spin" : ""}`} />
2025-10-13 15:17:34 +09:00
</Button>
<Button variant="default" onClick={handleOpenCreateModal}>
<Plus className="mr-2 h-4 w-4" />
2025-10-13 15:17:34 +09:00
</Button>
</div>
2025-10-01 16:15:53 +09:00
</div>
</div>
{/* 메인 컨텐츠 */}
{loading ? (
2025-10-13 15:17:34 +09:00
<Card>
<CardContent className="flex items-center justify-center py-16">
<Loader2 className="text-primary h-8 w-8 animate-spin" />
2025-10-01 16:15:53 +09:00
</CardContent>
</Card>
) : (
2025-10-13 15:17:34 +09:00
<Card>
2025-10-01 16:15:53 +09:00
<CardContent className="p-6">
<MailAccountTable
accounts={accounts}
onEdit={handleOpenEditModal}
onDelete={handleOpenDeleteModal}
onToggleStatus={handleToggleStatus}
2025-10-02 15:46:23 +09:00
onTestConnection={handleTestConnection}
2025-10-01 16:15:53 +09:00
/>
</CardContent>
</Card>
)}
{/* 안내 정보 */}
2025-10-13 15:17:34 +09:00
<Card className="bg-muted/50">
2025-10-01 16:15:53 +09:00
<CardHeader>
<CardTitle className="flex items-center text-lg">
<Mail className="text-foreground mr-2 h-5 w-5" />
2025-10-01 16:15:53 +09:00
</CardTitle>
</CardHeader>
<CardContent>
<p className="text-foreground mb-4">💡 SMTP !</p>
<ul className="text-muted-foreground space-y-2 text-sm">
2025-10-01 16:15:53 +09:00
<li className="flex items-start">
2025-10-13 15:17:34 +09:00
<span className="text-foreground mr-2"></span>
2025-10-01 16:15:53 +09:00
<span>Gmail, Naver, SMTP </span>
</li>
<li className="flex items-start">
2025-10-13 15:17:34 +09:00
<span className="text-foreground mr-2"></span>
2025-10-01 16:15:53 +09:00
<span> </span>
</li>
<li className="flex items-start">
2025-10-13 15:17:34 +09:00
<span className="text-foreground mr-2"></span>
2025-10-01 16:15:53 +09:00
<span> </span>
</li>
</ul>
</CardContent>
</Card>
</div>
{/* 모달들 */}
<MailAccountModal
isOpen={isModalOpen}
onClose={() => setIsModalOpen(false)}
onSave={handleSaveAccount}
account={selectedAccount}
mode={modalMode}
/>
<ConfirmDeleteModal
isOpen={isDeleteModalOpen}
onClose={() => setIsDeleteModalOpen(false)}
onConfirm={handleDeleteAccount}
title="메일 계정 삭제"
message="이 메일 계정을 삭제하시겠습니까?"
itemName={selectedAccount?.name}
/>
</div>
);
}