Neah/components/email/EmailContent.tsx
2025-04-26 23:51:33 +02:00

163 lines
5.4 KiB
TypeScript

'use client';
import React, { useState, useEffect } from 'react';
import { Loader2, Paperclip, FileDown, Download } from 'lucide-react';
import { sanitizeHtml } from '@/lib/utils/email-formatter';
import { Button } from '@/components/ui/button';
import { Email } from '@/hooks/use-courrier';
import { Alert, AlertDescription, AlertTitle } from '@/components/ui/alert';
import { ScrollArea } from '@/components/ui/scroll-area';
import { Avatar, AvatarFallback } from '@/components/ui/avatar';
interface EmailContentProps {
email: Email;
}
export default function EmailContent({ email }: EmailContentProps) {
const [content, setContent] = useState<React.ReactNode>(null);
const [isLoading, setIsLoading] = useState(false);
const [error, setError] = useState<string | null>(null);
useEffect(() => {
if (!email) return;
const renderContent = async () => {
setIsLoading(true);
setError(null);
try {
if (!email.content || email.content.length === 0) {
setContent(<div className="text-gray-500">Email content is empty</div>);
return;
}
// Use the sanitizer from the centralized formatter
const sanitizedHtml = sanitizeHtml(email.content);
// Look for specific markers that indicate this is a forwarded or replied email
const isForwarded = sanitizedHtml.includes('---------- Forwarded message ---------');
const isReply = sanitizedHtml.includes('class="reply-body"') ||
sanitizedHtml.includes('blockquote style="margin: 0; padding: 10px 0 10px 15px; border-left:');
// For forwarded or replied emails, ensure we keep the exact structure
if (isForwarded || isReply) {
setContent(
<div
className="email-content prose max-w-none"
dangerouslySetInnerHTML={{ __html: sanitizedHtml }}
dir="rtl"
style={{ textAlign: 'right' }}
/>
);
} else {
// For regular emails, wrap in the same structure used in the compose editor
setContent(
<div
className="email-content prose max-w-none"
dir="rtl"
style={{ textAlign: 'right' }}
>
<div style={{ minHeight: "20px" }} dir="rtl">
<div dangerouslySetInnerHTML={{ __html: sanitizedHtml }} />
</div>
</div>
);
}
} catch (err) {
console.error('Error rendering email content:', err);
setError('Error rendering email content. Please try again.');
setContent(null);
} finally {
setIsLoading(false);
}
};
renderContent();
}, [email]);
// Render attachments if they exist
const renderAttachments = () => {
if (!email?.attachments || email.attachments.length === 0) {
return null;
}
return (
<div className="mt-6 border-t border-gray-200 pt-6">
<h3 className="text-sm font-semibold text-gray-900 mb-4">Attachments</h3>
<div className="grid grid-cols-2 gap-4">
{email.attachments.map((attachment, index) => (
<div key={index} className="flex items-center space-x-2 p-2 border rounded hover:bg-gray-50">
<Paperclip className="h-4 w-4 text-gray-400" />
<span className="text-sm text-gray-600 truncate flex-1">
{attachment.filename}
</span>
<Download className="h-4 w-4 text-gray-400 hover:text-gray-600 cursor-pointer" />
</div>
))}
</div>
</div>
);
};
if (isLoading) {
return (
<div className="flex justify-center items-center h-full p-8">
<div className="animate-spin rounded-full h-8 w-8 border-t-2 border-b-2 border-blue-500"></div>
</div>
);
}
if (error) {
return (
<Alert variant="destructive" className="m-4">
<AlertTitle>Error</AlertTitle>
<AlertDescription>{error}</AlertDescription>
</Alert>
);
}
// Format the date for display
const formatDate = (dateObj: Date) => {
const now = new Date();
const today = new Date(now.getFullYear(), now.getMonth(), now.getDate());
const yesterday = new Date(today);
yesterday.setDate(yesterday.getDate() - 1);
const date = new Date(dateObj);
const formattedTime = date.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' });
if (date >= today) {
return formattedTime;
} else if (date >= yesterday) {
return `Yesterday, ${formattedTime}`;
} else {
return date.toLocaleDateString([], { month: 'short', day: 'numeric' });
}
};
return (
<div className="email-content p-6">
<div className="flex items-center gap-4 mb-6">
<Avatar className="h-10 w-10 bg-gray-100">
<AvatarFallback className="text-gray-600 font-medium">
{email.from?.[0]?.name?.[0] || email.from?.[0]?.address?.[0] || '?'}
</AvatarFallback>
</Avatar>
<div>
<p className="font-medium text-gray-900">
{email.from?.[0]?.name || email.from?.[0]?.address || 'Unknown'}
</p>
<p className="text-sm text-gray-500">
to {email.to?.[0]?.address || 'you'}
</p>
</div>
<div className="ml-auto text-sm text-gray-500">
{formatDate(new Date(email.date))}
</div>
</div>
{content}
{renderAttachments()}
</div>
);
}