177 lines
4.5 KiB
TypeScript
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>
|
|
);
|
|
}
|