135 lines
3.9 KiB
TypeScript
135 lines
3.9 KiB
TypeScript
'use client';
|
|
|
|
import React, { useState } from 'react';
|
|
import { Loader2, Paperclip, Download } from 'lucide-react';
|
|
import { sanitizeHtml } from '@/lib/utils/dom-purify-config';
|
|
import { Alert, AlertDescription, AlertTitle } from '@/components/ui/alert';
|
|
import { Avatar, AvatarFallback } from '@/components/ui/avatar';
|
|
|
|
interface EmailAddress {
|
|
name: string;
|
|
address: string;
|
|
}
|
|
|
|
interface Email {
|
|
id: string;
|
|
subject: string;
|
|
from: EmailAddress[];
|
|
to: EmailAddress[];
|
|
cc?: EmailAddress[];
|
|
bcc?: EmailAddress[];
|
|
date: Date | string;
|
|
content?: string;
|
|
html?: string;
|
|
text?: string;
|
|
hasAttachments?: boolean;
|
|
attachments?: Array<{
|
|
filename: string;
|
|
contentType: string;
|
|
size: number;
|
|
path?: string;
|
|
content?: string;
|
|
}>;
|
|
}
|
|
|
|
interface EmailContentProps {
|
|
email: Email;
|
|
}
|
|
|
|
export default function EmailContent({ email }: EmailContentProps) {
|
|
const [isLoading, setIsLoading] = useState(false);
|
|
const [error, setError] = useState<string | null>(null);
|
|
|
|
// 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">
|
|
<Loader2 className="h-8 w-8 animate-spin text-primary" />
|
|
</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-display 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>
|
|
|
|
{email.content ? (
|
|
<div className="email-content-display">
|
|
<div dangerouslySetInnerHTML={{ __html: sanitizeHtml(email.content) }} />
|
|
</div>
|
|
) : (
|
|
<p className="text-gray-500">No content available</p>
|
|
)}
|
|
|
|
{renderAttachments()}
|
|
</div>
|
|
);
|
|
}
|