161 lines
6.7 KiB
TypeScript
161 lines
6.7 KiB
TypeScript
'use client';
|
|
|
|
import { useState, useEffect } from 'react';
|
|
import { useSearchParams } from 'next/navigation';
|
|
import Link from 'next/link';
|
|
|
|
interface Email {
|
|
key: string;
|
|
subject: string;
|
|
date: string;
|
|
processed: string;
|
|
}
|
|
|
|
export default function Emails() {
|
|
const searchParams = useSearchParams();
|
|
const bucket = searchParams.get('bucket');
|
|
const mailbox = searchParams.get('mailbox');
|
|
const [emails, setEmails] = useState<Email[]>([]);
|
|
const [message, setMessage] = useState('');
|
|
const [error, setError] = useState<string | null>(null);
|
|
const [loading, setLoading] = useState(true);
|
|
|
|
useEffect(() => {
|
|
if (!bucket || !mailbox) {
|
|
setError('Missing parameters');
|
|
setLoading(false);
|
|
return;
|
|
}
|
|
const auth = localStorage.getItem('auth');
|
|
if (!auth) {
|
|
setError('Not authenticated');
|
|
setLoading(false);
|
|
return;
|
|
}
|
|
|
|
fetch(`/api/emails?bucket=${bucket}&mailbox=${encodeURIComponent(mailbox)}`, {
|
|
headers: { Authorization: `Basic ${auth}` }
|
|
})
|
|
.then(res => {
|
|
if (!res.ok) throw new Error('Failed to fetch emails');
|
|
return res.json();
|
|
})
|
|
.then(data => {
|
|
// Sortiere nach date descending
|
|
const sorted = data.sort((a: Email, b: Email) => new Date(b.date).getTime() - new Date(a.date).getTime());
|
|
setEmails(sorted);
|
|
})
|
|
.catch(err => setError(err.message))
|
|
.finally(() => setLoading(false));
|
|
}, [bucket, mailbox]);
|
|
|
|
if (loading) return <div className="min-h-screen flex items-center justify-center bg-gray-100">Loading...</div>;
|
|
if (error) return <div className="min-h-screen flex items-center justify-center bg-gray-100 text-red-500">{error}</div>;
|
|
|
|
const formatDate = (dateStr: string) => {
|
|
const date = new Date(dateStr);
|
|
return date.toLocaleString('en-US', { year: 'numeric', month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit', hour12: false });
|
|
};
|
|
|
|
const handleResendAll = async () => {
|
|
const auth = localStorage.getItem('auth');
|
|
if (!auth) return setMessage('Not authenticated');
|
|
|
|
const response = await fetch('/api/resend-domain', {
|
|
method: 'POST',
|
|
headers: { Authorization: `Basic ${auth}`, 'Content-Type': 'application/json' },
|
|
body: JSON.stringify({ bucket }),
|
|
});
|
|
const res = await response.json();
|
|
setMessage(res.message || res.error);
|
|
};
|
|
|
|
const handleUpdateProcessed = async (key: string, newValue: boolean) => {
|
|
const auth = localStorage.getItem('auth');
|
|
if (!auth) return;
|
|
|
|
await fetch('/api/email', {
|
|
method: 'PUT',
|
|
headers: { Authorization: `Basic ${auth}`, 'Content-Type': 'application/json' },
|
|
body: JSON.stringify({ bucket, key, processed: newValue ? 'true' : 'false' }),
|
|
});
|
|
setEmails(emails.map(em => em.key === key ? { ...em, processed: newValue ? 'true' : 'false' } : em));
|
|
};
|
|
|
|
const handleResend = async (key: string) => {
|
|
const auth = localStorage.getItem('auth');
|
|
if (!auth) return alert('Not authenticated');
|
|
|
|
const response = await fetch('/api/email', {
|
|
method: 'POST',
|
|
headers: { Authorization: `Basic ${auth}`, 'Content-Type': 'application/json' },
|
|
body: JSON.stringify({ bucket, key }),
|
|
});
|
|
const res = await response.json();
|
|
alert(res.message || res.error);
|
|
};
|
|
|
|
return (
|
|
<div className="min-h-screen bg-gradient-to-b from-blue-50 to-gray-100 p-8">
|
|
<nav className="max-w-4xl mx-auto mb-6 bg-white p-4 rounded-lg shadow-sm">
|
|
<ol className="flex flex-wrap space-x-2 text-sm text-gray-500">
|
|
<li><Link href="/" className="hover:text-blue-600">Home</Link></li>
|
|
<li className="mx-1">/</li>
|
|
<li><Link href="/domains" className="hover:text-blue-600">Domains</Link></li>
|
|
<li className="mx-1">/</li>
|
|
<li><Link href={`/mailboxes?bucket=${bucket}`} className="hover:text-blue-600">Mailboxes</Link></li>
|
|
<li className="mx-1">/</li>
|
|
<li className="font-semibold text-gray-700">Emails</li>
|
|
</ol>
|
|
</nav>
|
|
<h1 className="text-4xl font-bold mb-8 text-center text-gray-800">Emails for {mailbox} in {bucket}</h1>
|
|
<div className="flex justify-center mb-6">
|
|
<button
|
|
onClick={handleResendAll}
|
|
className="bg-green-500 text-white px-8 py-3 rounded-lg hover:bg-green-600 transition shadow-md"
|
|
>
|
|
Resend all unprocessed
|
|
</button>
|
|
</div>
|
|
{message && <p className="text-center mb-6 text-blue-600 font-medium">{message}</p>}
|
|
<div className="overflow-x-auto max-w-4xl mx-auto bg-white rounded-lg shadow-md">
|
|
<table className="min-w-full divide-y divide-gray-200">
|
|
<thead className="bg-blue-50">
|
|
<tr>
|
|
<th className="px-6 py-3 text-left text-xs font-medium text-gray-700 uppercase tracking-wider">Subject</th>
|
|
<th className="px-6 py-3 text-left text-xs font-medium text-gray-700 uppercase tracking-wider">Date</th>
|
|
<th className="px-6 py-3 text-left text-xs font-medium text-gray-700 uppercase tracking-wider">S3 Key</th>
|
|
<th className="px-6 py-3 text-left text-xs font-medium text-gray-700 uppercase tracking-wider">Processed</th>
|
|
<th className="px-6 py-3 text-left text-xs font-medium text-gray-700 uppercase tracking-wider">Actions</th>
|
|
</tr>
|
|
</thead>
|
|
<tbody className="bg-white divide-y divide-gray-200">
|
|
{emails.map((e: Email) => (
|
|
<tr key={e.key} className="hover:bg-blue-50 transition">
|
|
<td className="px-6 py-4 whitespace-nowrap text-sm text-gray-900">{e.subject}</td>
|
|
<td className="px-6 py-4 whitespace-nowrap text-sm text-gray-500">{formatDate(e.date)}</td>
|
|
<td className="px-6 py-4 whitespace-nowrap text-sm text-gray-500 truncate max-w-xs">{e.key}</td>
|
|
<td className="px-6 py-4 whitespace-nowrap text-sm text-gray-500">
|
|
<input
|
|
type="checkbox"
|
|
checked={e.processed === 'true'}
|
|
onChange={() => handleUpdateProcessed(e.key, e.processed !== 'true')}
|
|
className="h-4 w-4 text-blue-600 focus:ring-blue-500 border-gray-300 rounded"
|
|
/>
|
|
</td>
|
|
<td className="px-6 py-4 whitespace-nowrap text-sm font-medium">
|
|
<Link href={`/email?bucket=${bucket}&key=${e.key}&mailbox=${encodeURIComponent(mailbox || '')}`} className="text-blue-600 hover:text-blue-900 mr-4">
|
|
View
|
|
</Link>
|
|
<button onClick={() => handleResend(e.key)} className="text-green-600 hover:text-green-900">
|
|
Resend
|
|
</button>
|
|
</td>
|
|
</tr>
|
|
))}
|
|
</tbody>
|
|
</table>
|
|
</div>
|
|
</div>
|
|
);
|
|
} |