mail page imap connection 2

This commit is contained in:
alma 2025-04-15 20:21:16 +02:00
parent 4836353591
commit ea4de624eb
2 changed files with 77 additions and 35 deletions

View File

@ -6,12 +6,25 @@ import { simpleParser } from 'mailparser';
const imapConfig = {
user: 'contact@governance-labs.org',
password: 'K!376c$6H#kMknM',
host: 'mail.governance-labs.org',
host: 'mail.infomniak.com',
port: 993,
tls: true,
tlsOptions: { rejectUnauthorized: false }
};
interface ImapMessage {
header: {
from: string[];
to: string[];
subject: string[];
date: string[];
};
body: string;
attributes: {
flags: string[];
};
}
// Helper function to create a promise-based IMAP connection
function createImapConnection() {
return new Promise((resolve, reject) => {
@ -24,7 +37,7 @@ function createImapConnection() {
}
// Helper function to promisify the message fetching
function fetchMessages(imap: Imap, box: string) {
function fetchMessages(imap: Imap, box: string): Promise<ImapMessage[]> {
return new Promise((resolve, reject) => {
imap.openBox(box, false, (err, mailbox) => {
if (err) {
@ -50,10 +63,10 @@ function fetchMessages(imap: Imap, box: string) {
struct: true
});
const messages: any[] = [];
const messages: ImapMessage[] = [];
fetch.on('message', (msg) => {
const message: any = {};
const message: Partial<ImapMessage> = {};
msg.on('body', (stream, info) => {
let buffer = '';
@ -74,7 +87,7 @@ function fetchMessages(imap: Imap, box: string) {
});
msg.once('end', () => {
messages.push(message);
messages.push(message as ImapMessage);
});
});
@ -96,7 +109,7 @@ export async function GET(request: Request) {
const messages = await fetchMessages(imap, 'INBOX');
// Process messages into the format expected by the frontend
const processedMessages = messages.map((msg: any, index: number) => ({
const processedMessages = messages.map((msg: ImapMessage, index: number) => ({
id: index + 1,
accountId: 1,
from: msg.header.from[0],

View File

@ -3,7 +3,7 @@
import { Card } from "@/components/ui/card"
import { Button } from "@/components/ui/button"
import { Input } from "@/components/ui/input"
import { Mail, Search, Star, Inbox, Send, Archive, Trash } from "lucide-react"
import { Mail, Search, Star, Inbox, Send, Archive, Trash, AlertCircle } from "lucide-react"
import { useState, useEffect } from "react"
interface Email {
@ -23,16 +23,23 @@ interface Email {
export default function MailPage() {
const [emails, setEmails] = useState<Email[]>([])
const [loading, setLoading] = useState(true)
const [error, setError] = useState<string | null>(null)
useEffect(() => {
async function fetchEmails() {
try {
setError(null)
const res = await fetch('/api/mail')
if (!res.ok) throw new Error('Failed to fetch emails')
if (!res.ok) {
const errorData = await res.json().catch(() => ({}))
throw new Error(errorData.error || 'Failed to fetch emails')
}
const data = await res.json()
setEmails(data.messages)
setEmails(data.messages || [])
} catch (error) {
console.error('Error fetching emails:', error)
setError('Unable to connect to mail server. Please try again later.')
setEmails([])
} finally {
setLoading(false)
}
@ -96,39 +103,61 @@ export default function MailPage() {
<div className="flex items-center justify-center h-full">
<p className="text-gray-500">Loading emails...</p>
</div>
) : error ? (
<div className="flex flex-col items-center justify-center h-full text-center">
<AlertCircle className="h-12 w-12 text-yellow-500 mb-4" />
<p className="text-gray-600 mb-2">{error}</p>
<Button
variant="outline"
onClick={() => {
setLoading(true)
setError(null)
fetchEmails()
}}
>
Try Again
</Button>
</div>
) : (
<div className="space-y-2">
{emails.map((email) => (
<Card key={email.id} className={`p-4 hover:bg-gray-50 cursor-pointer ${!email.read ? 'bg-blue-50' : ''}`}>
<div className="flex items-center gap-4">
<Button
variant="ghost"
size="icon"
className="h-4 w-4 p-0"
onClick={(e) => {
e.stopPropagation()
// TODO: Implement star functionality
}}
>
<Star className={`h-4 w-4 ${email.starred ? 'fill-yellow-400 text-yellow-400' : 'text-gray-400'}`} />
</Button>
<div className="flex-1 min-w-0">
<div className="flex items-center gap-2">
<p className="font-medium truncate">{email.fromName}</p>
<span className="text-sm text-gray-500">
{new Date(email.date).toLocaleDateString()}
</span>
{emails.length === 0 ? (
<div className="flex flex-col items-center justify-center h-[calc(100vh-12rem)] text-center">
<Mail className="h-12 w-12 text-gray-400 mb-4" />
<p className="text-gray-600">No emails found</p>
</div>
) : (
emails.map((email) => (
<Card key={email.id} className={`p-4 hover:bg-gray-50 cursor-pointer ${!email.read ? 'bg-blue-50' : ''}`}>
<div className="flex items-center gap-4">
<Button
variant="ghost"
size="icon"
className="h-4 w-4 p-0"
onClick={(e) => {
e.stopPropagation()
// TODO: Implement star functionality
}}
>
<Star className={`h-4 w-4 ${email.starred ? 'fill-yellow-400 text-yellow-400' : 'text-gray-400'}`} />
</Button>
<div className="flex-1 min-w-0">
<div className="flex items-center gap-2">
<p className="font-medium truncate">{email.fromName}</p>
<span className="text-sm text-gray-500">
{new Date(email.date).toLocaleDateString()}
</span>
</div>
<p className="text-sm font-medium truncate">{email.subject}</p>
<p className="text-sm text-gray-500 truncate">{email.body}</p>
</div>
<p className="text-sm font-medium truncate">{email.subject}</p>
<p className="text-sm text-gray-500 truncate">{email.body}</p>
</div>
</div>
</Card>
))}
</Card>
))
)}
</div>
)}
</main>
</div>
</div>
)
}
}