'use client'; import { useState, useEffect, useMemo } from 'react'; import { useSearchParams } from 'next/navigation'; import Link from 'next/link'; import { AppHeader } from '@/components/layout/AppHeader'; import { Sidebar } from '@/components/layout/Sidebar'; import { Breadcrumb } from '@/components/layout/Breadcrumb'; import { TableSkeleton } from '@/components/ui/Skeleton'; interface Email { key: string; subject: string; from: string; to: string[]; preview?: string; date: string; processed: string; processedAt: string | null; processedBy: string | null; queuedTo: string | null; status: string | null; } export default function Emails() { const searchParams = useSearchParams(); const bucket = searchParams.get('bucket'); const mailbox = searchParams.get('mailbox'); const [emails, setEmails] = useState([]); const [error, setError] = useState(null); const [loading, setLoading] = useState(true); const [searchQuery, setSearchQuery] = useState(''); const [statusFilter, setStatusFilter] = useState('all'); const [dateFilter, setDateFilter] = useState('all'); const [sortBy, setSortBy] = useState<'newest' | 'oldest' | 'subject'>('newest'); 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 => { setEmails(data); }) .catch(err => setError(err.message)) .finally(() => setLoading(false)); }, [bucket, mailbox]); // Filter and search emails const filteredEmails = useMemo(() => { let result = [...emails]; // Apply status filter if (statusFilter !== 'all') { result = result.filter(e => e.status === statusFilter); } // Apply date filter if (dateFilter !== 'all') { const now = new Date(); const today = new Date(now.getFullYear(), now.getMonth(), now.getDate()); result = result.filter(e => { const emailDate = new Date(e.date); const emailDay = new Date(emailDate.getFullYear(), emailDate.getMonth(), emailDate.getDate()); const daysDiff = Math.floor((today.getTime() - emailDay.getTime()) / (1000 * 60 * 60 * 24)); switch (dateFilter) { case 'today': return daysDiff === 0; case 'yesterday': return daysDiff === 1; case 'last2days': return daysDiff <= 1; case 'last3days': return daysDiff <= 2; case '2daysago': return daysDiff === 2; case '3daysago': return daysDiff === 3; case '4daysago': return daysDiff === 4; case '5daysago': return daysDiff === 5; case 'lastweek': return daysDiff <= 7; case 'lastmonth': return daysDiff <= 30; default: return true; } }); } // Apply search if (searchQuery.trim()) { const query = searchQuery.toLowerCase(); result = result.filter(e => e.subject.toLowerCase().includes(query) || (e.from && e.from.toLowerCase().includes(query)) || (e.to && Array.isArray(e.to) && e.to.some(addr => addr.toLowerCase().includes(query))) ); } // Apply sorting if (sortBy === 'newest') { result.sort((a, b) => new Date(b.date).getTime() - new Date(a.date).getTime()); } else if (sortBy === 'oldest') { result.sort((a, b) => new Date(a.date).getTime() - new Date(b.date).getTime()); } else if (sortBy === 'subject') { result.sort((a, b) => a.subject.localeCompare(b.subject)); } return result; }, [emails, statusFilter, dateFilter, searchQuery, sortBy]); // Calculate stats const stats = useMemo(() => { const total = emails.length; const delivered = emails.filter(e => e.status === 'delivered').length; const failed = emails.filter(e => e.status === 'failed').length; const pending = emails.filter(e => !e.status || e.status === 'pending').length; return { total, delivered, failed, pending }; }, [emails]); const formatDate = (dateStr: string) => { const date = new Date(dateStr); const now = new Date(); const diff = now.getTime() - date.getTime(); const days = Math.floor(diff / (1000 * 60 * 60 * 24)); if (days === 0) { return date.toLocaleTimeString('de-DE', { hour: '2-digit', minute: '2-digit' }); } else if (days < 7) { return date.toLocaleDateString('de-DE', { weekday: 'short' }); } else { return date.toLocaleDateString('de-DE', { month: 'short', day: 'numeric' }); } }; if (error) { return ( <>

{error}

); } return ( <>
{/* Page Header with Stats */}

{mailbox}

{/* Stats */}
{stats.total}
Total
{stats.delivered}
Delivered
{stats.failed}
Failed
{stats.pending}
Pending
{/* Filter & Toolbar */}
{/* Search */}
setSearchQuery(e.target.value)} className="w-full pl-10 pr-4 py-2 bg-gray-100 rounded-lg focus:bg-white focus:ring-2 focus:ring-blue-500 focus:outline-none transition-all text-sm" />
{/* Date Filter */}
{/* Status Filter Chips */}
{/* Sort & View Options */}
{/* Email List (Gmail-Style) */}
{loading ? (
) : filteredEmails.length === 0 ? (

Keine E-Mails gefunden

{searchQuery && ( )}
) : ( <> {filteredEmails.map((email) => (
{/* From - breiter und mit Tooltip */}
{email.from || 'Unknown'}
{/* Subject & Preview - klickbar */}
{email.subject || '(No Subject)'}
{email.preview && (
{email.preview}
)} {/* S3 Key Column - kopierbar */}
{email.key}
{/* Status Badge */}
{email.status && ( {email.status === 'delivered' && ( )} {email.status === 'failed' && ( )} {email.status} )}
{/* Date & Time */}
{new Date(email.date).toLocaleDateString('de-DE', { day: '2-digit', month: '2-digit', year: 'numeric' })}
{new Date(email.date).toLocaleTimeString('de-DE', { hour: '2-digit', minute: '2-digit' })}
))} )}
{!loading && (
{filteredEmails.length} emails loaded
)}
); }