courrier refactor rebuild preview
This commit is contained in:
parent
c7f5e31b23
commit
a2a088cf0f
@ -1,11 +1,14 @@
|
|||||||
'use client';
|
'use client';
|
||||||
|
|
||||||
import { useState } from 'react';
|
import { useState } from 'react';
|
||||||
import { Loader2, Paperclip } from 'lucide-react';
|
import { Loader2, Paperclip, User } from 'lucide-react';
|
||||||
import { Button } from '@/components/ui/button';
|
import { Button } from '@/components/ui/button';
|
||||||
import { Badge } from '@/components/ui/badge';
|
import { Badge } from '@/components/ui/badge';
|
||||||
import { ScrollArea } from '@/components/ui/scroll-area';
|
import { ScrollArea } from '@/components/ui/scroll-area';
|
||||||
import { sanitizeHtml } from '@/lib/utils/email-formatter';
|
import { sanitizeHtml } from '@/lib/utils/email-formatter';
|
||||||
|
import { Avatar } from '@/components/ui/avatar';
|
||||||
|
import { AvatarFallback, AvatarImage } from '@/components/ui/avatar';
|
||||||
|
import { Card } from '@/components/ui/card';
|
||||||
|
|
||||||
interface EmailAddress {
|
interface EmailAddress {
|
||||||
name: string;
|
name: string;
|
||||||
@ -78,6 +81,19 @@ export default function EmailPreview({ email, loading = false, onReply }: EmailP
|
|||||||
).join(', ');
|
).join(', ');
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Get sender initials for avatar
|
||||||
|
const getSenderInitials = (sender: EmailAddress | undefined) => {
|
||||||
|
if (!sender) return 'U';
|
||||||
|
if (sender.name) {
|
||||||
|
const parts = sender.name.split(' ');
|
||||||
|
if (parts.length > 1) {
|
||||||
|
return `${parts[0][0]}${parts[parts.length - 1][0]}`.toUpperCase();
|
||||||
|
}
|
||||||
|
return sender.name[0].toUpperCase();
|
||||||
|
}
|
||||||
|
return sender.address[0].toUpperCase();
|
||||||
|
};
|
||||||
|
|
||||||
// Display loading state
|
// Display loading state
|
||||||
if (loading) {
|
if (loading) {
|
||||||
return (
|
return (
|
||||||
@ -101,70 +117,74 @@ export default function EmailPreview({ email, loading = false, onReply }: EmailP
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const sender = email.from && email.from.length > 0 ? email.from[0] : undefined;
|
||||||
|
|
||||||
return (
|
return (
|
||||||
<div className="flex flex-col h-full overflow-hidden">
|
<Card className="flex flex-col h-full overflow-hidden border-0 shadow-none">
|
||||||
{/* Email header */}
|
{/* Email header */}
|
||||||
<div className="p-4 border-b">
|
<div className="p-6 border-b">
|
||||||
<div className="mb-3">
|
<div className="mb-4">
|
||||||
<h2 className="text-xl font-semibold mb-2">{email.subject}</h2>
|
<h2 className="text-xl font-semibold mb-4">{email.subject}</h2>
|
||||||
<div className="flex items-center justify-between text-sm">
|
|
||||||
<div className="flex items-center">
|
<div className="flex items-start gap-3 mb-4">
|
||||||
<span className="font-medium mr-1">From:</span>
|
<Avatar className="h-10 w-10">
|
||||||
<span>{formatEmailAddresses(email.from)}</span>
|
<AvatarFallback>{getSenderInitials(sender)}</AvatarFallback>
|
||||||
|
</Avatar>
|
||||||
|
|
||||||
|
<div className="flex-1 min-w-0">
|
||||||
|
<div className="flex items-center justify-between">
|
||||||
|
<div className="font-medium">{sender?.name || sender?.address}</div>
|
||||||
|
<span className="text-sm text-muted-foreground">{formatDate(email.date)}</span>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div className="text-sm text-muted-foreground truncate mt-1">
|
||||||
|
To: {formatEmailAddresses(email.to)}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
{email.cc && email.cc.length > 0 && (
|
||||||
|
<div className="text-sm text-muted-foreground truncate mt-1">
|
||||||
|
Cc: {formatEmailAddresses(email.cc)}
|
||||||
|
</div>
|
||||||
|
)}
|
||||||
</div>
|
</div>
|
||||||
<span className="text-muted-foreground">{formatDate(email.date)}</span>
|
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{email.to && email.to.length > 0 && (
|
{/* Action buttons */}
|
||||||
<div className="text-sm mt-1">
|
{onReply && (
|
||||||
<span className="font-medium mr-1">To:</span>
|
<div className="flex gap-2 mt-4">
|
||||||
<span>{formatEmailAddresses(email.to)}</span>
|
<Button
|
||||||
</div>
|
size="sm"
|
||||||
)}
|
variant="outline"
|
||||||
|
onClick={() => onReply('reply')}
|
||||||
{email.cc && email.cc.length > 0 && (
|
>
|
||||||
<div className="text-sm mt-1">
|
Reply
|
||||||
<span className="font-medium mr-1">Cc:</span>
|
</Button>
|
||||||
<span>{formatEmailAddresses(email.cc)}</span>
|
<Button
|
||||||
|
size="sm"
|
||||||
|
variant="outline"
|
||||||
|
onClick={() => onReply('reply-all')}
|
||||||
|
>
|
||||||
|
Reply All
|
||||||
|
</Button>
|
||||||
|
<Button
|
||||||
|
size="sm"
|
||||||
|
variant="outline"
|
||||||
|
onClick={() => onReply('forward')}
|
||||||
|
>
|
||||||
|
Forward
|
||||||
|
</Button>
|
||||||
</div>
|
</div>
|
||||||
)}
|
)}
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Action buttons */}
|
|
||||||
{onReply && (
|
|
||||||
<div className="flex gap-2 mt-4">
|
|
||||||
<Button
|
|
||||||
size="sm"
|
|
||||||
variant="outline"
|
|
||||||
onClick={() => onReply('reply')}
|
|
||||||
>
|
|
||||||
Reply
|
|
||||||
</Button>
|
|
||||||
<Button
|
|
||||||
size="sm"
|
|
||||||
variant="outline"
|
|
||||||
onClick={() => onReply('reply-all')}
|
|
||||||
>
|
|
||||||
Reply All
|
|
||||||
</Button>
|
|
||||||
<Button
|
|
||||||
size="sm"
|
|
||||||
variant="outline"
|
|
||||||
onClick={() => onReply('forward')}
|
|
||||||
>
|
|
||||||
Forward
|
|
||||||
</Button>
|
|
||||||
</div>
|
|
||||||
)}
|
|
||||||
|
|
||||||
{/* Attachments */}
|
{/* Attachments */}
|
||||||
{email.attachments && email.attachments.length > 0 && (
|
{email.attachments && email.attachments.length > 0 && (
|
||||||
<div className="mt-4 border-t pt-2">
|
<div className="px-6 py-3 border-b bg-muted/30">
|
||||||
<div className="text-sm font-medium mb-2">Attachments:</div>
|
<div className="text-sm font-medium mb-2">Attachments</div>
|
||||||
<div className="flex flex-wrap gap-2">
|
<div className="flex flex-wrap gap-2">
|
||||||
{email.attachments.map((attachment, index) => (
|
{email.attachments.map((attachment, index) => (
|
||||||
<Badge key={index} variant="outline" className="flex items-center gap-1">
|
<Badge key={index} variant="outline" className="flex items-center gap-1 px-2 py-1">
|
||||||
<Paperclip className="h-3 w-3" />
|
<Paperclip className="h-3.5 w-3.5" />
|
||||||
<span>{attachment.filename}</span>
|
<span>{attachment.filename}</span>
|
||||||
<span className="text-xs text-muted-foreground ml-1">
|
<span className="text-xs text-muted-foreground ml-1">
|
||||||
({Math.round(attachment.size / 1024)}KB)
|
({Math.round(attachment.size / 1024)}KB)
|
||||||
@ -177,18 +197,20 @@ export default function EmailPreview({ email, loading = false, onReply }: EmailP
|
|||||||
</div>
|
</div>
|
||||||
|
|
||||||
{/* Email content */}
|
{/* Email content */}
|
||||||
<ScrollArea className="flex-1 px-4 py-3">
|
<ScrollArea className="flex-1">
|
||||||
{email.content ? (
|
<div className="px-6 py-5">
|
||||||
<div
|
{email.content ? (
|
||||||
className="email-content-display"
|
<div
|
||||||
dangerouslySetInnerHTML={{
|
className="email-content-display prose prose-sm max-w-none"
|
||||||
__html: sanitizeHtml(email.content)
|
dangerouslySetInnerHTML={{
|
||||||
}}
|
__html: sanitizeHtml(email.content)
|
||||||
/>
|
}}
|
||||||
) : (
|
/>
|
||||||
<p className="text-muted-foreground">No content available</p>
|
) : (
|
||||||
)}
|
<p className="text-muted-foreground">No content available</p>
|
||||||
|
)}
|
||||||
|
</div>
|
||||||
</ScrollArea>
|
</ScrollArea>
|
||||||
</div>
|
</Card>
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
Loading…
Reference in New Issue
Block a user