Neah/components/email/EmailPanel.tsx
2025-04-26 09:22:51 +02:00

177 lines
4.5 KiB
TypeScript

'use client';
import { useState, useEffect } from 'react';
import { EmailMessage } from '@/lib/services/email-service';
import EmailPreview from './EmailPreview';
import ComposeEmail from './ComposeEmail';
import { Loader2 } from 'lucide-react';
interface EmailPanelProps {
selectedEmailId: string | null;
folder?: string;
onSendEmail: (emailData: {
to: string;
cc?: string;
bcc?: string;
subject: string;
body: string;
attachments?: Array<{
name: string;
content: string;
type: string;
}>;
}) => Promise<void>;
}
export default function EmailPanel({
selectedEmailId,
folder = 'INBOX',
onSendEmail
}: EmailPanelProps) {
const [email, setEmail] = useState<EmailMessage | null>(null);
const [loading, setLoading] = useState<boolean>(false);
const [error, setError] = useState<string | null>(null);
// Compose mode state
const [isComposing, setIsComposing] = useState<boolean>(false);
const [composeType, setComposeType] = useState<'new' | 'reply' | 'reply-all' | 'forward'>('new');
// Load email content when selectedEmailId changes
useEffect(() => {
if (selectedEmailId) {
fetchEmail(selectedEmailId);
// Close compose mode when selecting a different email
setIsComposing(false);
} else {
setEmail(null);
}
}, [selectedEmailId, folder]);
// Fetch the email content
const fetchEmail = async (id: string) => {
setLoading(true);
setError(null);
try {
const response = await fetch(`/api/courrier/${id}?folder=${encodeURIComponent(folder)}`);
if (!response.ok) {
const errorData = await response.json();
throw new Error(errorData.error || 'Failed to fetch email');
}
const data = await response.json();
if (!data) {
throw new Error('Email not found');
}
// Mark as read if not already
if (!data.flags?.seen) {
markAsRead(id);
}
setEmail(data);
} catch (err) {
console.error('Error fetching email:', err);
setError(err instanceof Error ? err.message : 'Failed to load email');
} finally {
setLoading(false);
}
};
// Mark email as read
const markAsRead = async (id: string) => {
try {
await fetch(`/api/courrier/${id}/mark-read`, {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ action: 'mark-read' }),
});
} catch (err) {
console.error('Error marking email as read:', err);
}
};
// Handle reply/forward actions
const handleReply = (type: 'reply' | 'reply-all' | 'forward') => {
setComposeType(type);
setIsComposing(true);
};
// Handle compose mode close
const handleComposeClose = () => {
setIsComposing(false);
setComposeType('new');
};
// If no email is selected and not composing
if (!selectedEmailId && !isComposing) {
return (
<div className="h-full flex items-center justify-center">
<div className="text-center text-muted-foreground">
<p>Select an email to view or</p>
<button
className="text-primary mt-2 hover:underline"
onClick={() => {
setComposeType('new');
setIsComposing(true);
}}
>
Compose a new message
</button>
</div>
</div>
);
}
// Show loading state
if (loading) {
return (
<div className="h-full flex items-center justify-center">
<div className="text-center">
<Loader2 className="h-8 w-8 animate-spin mx-auto mb-4 text-primary" />
<p>Loading email...</p>
</div>
</div>
);
}
// Show error state
if (error) {
return (
<div className="h-full flex items-center justify-center">
<div className="text-center text-destructive">
<p>{error}</p>
<button
className="text-primary mt-2 hover:underline"
onClick={() => selectedEmailId && fetchEmail(selectedEmailId)}
>
Try again
</button>
</div>
</div>
);
}
// Show compose mode or email preview
return (
<div className="h-full">
{isComposing ? (
<ComposeEmail
initialEmail={email}
type={composeType}
onClose={handleComposeClose}
onSend={onSendEmail}
/>
) : (
<EmailPreview
email={email}
onReply={handleReply}
/>
)}
</div>
);
}