Files
webmailserver/app/[lang]/dashboard/logs/page.tsx

132 lines
4.5 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"use client";
import { useState, useEffect } from "react";
import { useDictionary } from "@/components/DictionaryContext";
interface Log {
id: string;
mailbox: string;
sender: string | null;
subject: string | null;
status: string;
error: string | null;
createdAt: string;
user?: {
name: string | null;
email: string;
} | null;
}
export default function LogsPage() {
const [logs, setLogs] = useState<Log[]>([]);
const [loading, setLoading] = useState(true);
const dict = useDictionary();
const fetchLogs = async () => {
setLoading(true);
try {
const res = await fetch("/api/logs");
if (!res.ok) {
const errorData = await res.json().catch(() => ({}));
throw new Error(errorData.error || `HTTP error! status: ${res.status}`);
}
const data = await res.json();
if (Array.isArray(data)) setLogs(data);
} catch (error: any) {
console.error("Failed to fetch logs:", error);
alert(error.message);
} finally {
setLoading(false);
}
};
useEffect(() => {
fetchLogs();
}, []);
return (
<>
<div className="page-header">
<div>
<h1 className="page-title">{dict.logs?.title || "Bildirim Logları"}</h1>
<p className="page-subtitle">{dict.logs?.subtitle || "Son gönderilen bildirimlerin durumu"}</p>
</div>
<button className="btn btn-ghost" onClick={fetchLogs} disabled={loading}>
<RefreshIcon />
</button>
</div>
<div className="page-body">
<div className="table-wrap">
{loading ? (
<div className="empty-state">
<span className="spinner" style={{ width: 24, height: 24 }} />
</div>
) : logs.length === 0 ? (
<div className="empty-state">
<div style={{ fontWeight: 600 }}>{dict.logs?.noLogs || "Log kaydı bulunamadı"}</div>
</div>
) : (
<table>
<thead>
<tr>
<th>{dict.logs?.mailbox || "Alıcı"}</th>
<th>{dict.logs?.sender || "Gönderen"} / {dict.logs?.subject || "Konu"}</th>
<th>{dict.logs?.status || "Durum"}</th>
<th>{dict.logs?.date || "Tarih"}</th>
</tr>
</thead>
<tbody>
{logs.map((log) => (
<tr key={log.id}>
<td>
<div style={{ fontWeight: 500 }}>{log.mailbox}</div>
{log.user && (
<div style={{ fontSize: 11, color: "var(--text-secondary)" }}>
{log.user.name || log.user.email}
</div>
)}
</td>
<td>
<div style={{ fontSize: 13, fontWeight: 500 }}>{log.sender || "Unknown"}</div>
<div style={{ fontSize: 12, color: "var(--text-secondary)", maxWidth: 300, overflow: "hidden", textOverflow: "ellipsis", whiteSpace: "nowrap" }}>
{log.subject || "(No Subject)"}
</div>
</td>
<td>
<div style={{ display: "flex", flexDirection: "column", gap: 4 }}>
<span className={`badge ${log.status === "SENT" ? "badge-green" : "badge-red"}`} style={{ width: "fit-content" }}>
{log.status === "SENT" ? (dict.logs?.sent || "GÖNDERİLDİ") : (dict.logs?.failed || "HATA")}
</span>
{log.error && (
<div style={{ fontSize: 10, color: "var(--text-red)", maxWidth: 200, wordBreak: "break-word" }}>
{log.error}
</div>
)}
</div>
</td>
<td style={{ fontSize: 12, color: "var(--text-secondary)" }}>
{new Date(log.createdAt).toLocaleString()}
</td>
</tr>
))}
</tbody>
</table>
)}
</div>
</div>
</>
);
}
function RefreshIcon() {
return (
<svg width="15" height="15" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round">
<path d="M3 12a9 9 0 0 1 9-9 9.75 9.75 0 0 1 6.74 2.74L21 8" />
<path d="M21 3v5h-5" />
<path d="M21 12a9 9 0 0 1-9 9 9.75 9.75 0 0 1-6.74-2.74L3 16" />
<path d="M3 21v-5h5" />
</svg>
);
}