mail-s3-admin/app/emails/page.tsx

139 lines
5.4 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(setEmails)
.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 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-gray-100 p-8">
<h1 className="text-3xl font-bold mb-6 text-center">Emails for {mailbox} in {bucket}</h1>
<div className="flex justify-center mb-6">
<button
onClick={handleResendAll}
className="bg-green-500 text-white px-6 py-3 rounded hover:bg-green-600 transition"
>
Resend all unprocessed
</button>
</div>
{message && <p className="text-center mb-4 text-blue-500">{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-gray-50">
<tr>
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Subject</th>
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Date</th>
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 uppercase tracking-wider">Processed</th>
<th className="px-6 py-3 text-left text-xs font-medium text-gray-500 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-gray-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">{e.date}</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}`} 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>
);
}