attachments courrier

This commit is contained in:
alma 2026-01-18 15:03:26 +01:00
parent 807200d9e4
commit f769d15bb1
2 changed files with 73 additions and 20 deletions

View File

@ -1,6 +1,6 @@
import React from 'react'; import React from 'react';
import { import {
ChevronLeft, Reply, ReplyAll, Forward, Star, MoreHorizontal ChevronLeft, Reply, ReplyAll, Forward, Star, MoreHorizontal, Eye, Download
} from 'lucide-react'; } from 'lucide-react';
import { ScrollArea } from '@/components/ui/scroll-area'; import { ScrollArea } from '@/components/ui/scroll-area';
import { Avatar, AvatarFallback } from '@/components/ui/avatar'; import { Avatar, AvatarFallback } from '@/components/ui/avatar';
@ -191,6 +191,7 @@ export default function EmailDetailView({
const handleDownload = async (e: React.MouseEvent) => { const handleDownload = async (e: React.MouseEvent) => {
e.preventDefault(); e.preventDefault();
e.stopPropagation();
try { try {
// Fetch the attachment // Fetch the attachment
const response = await fetch(downloadUrl); const response = await fetch(downloadUrl);
@ -219,29 +220,76 @@ export default function EmailDetailView({
} }
}; };
const handlePreview = async (e: React.MouseEvent) => {
e.preventDefault();
e.stopPropagation();
try {
// Fetch the attachment
const response = await fetch(downloadUrl);
if (!response.ok) {
throw new Error(`Failed to preview attachment: ${response.statusText}`);
}
// Get the blob
const blob = await response.blob();
// Check if it's an image or PDF that can be previewed
const contentType = attachment.contentType || response.headers.get('content-type') || '';
const isImage = contentType.startsWith('image/');
const isPDF = contentType === 'application/pdf';
const isText = contentType.startsWith('text/');
if (isImage || isPDF || isText) {
// Create a temporary URL and open in new tab
const url = window.URL.createObjectURL(blob);
window.open(url, '_blank');
// Cleanup after a delay (browser will keep it open)
setTimeout(() => window.URL.revokeObjectURL(url), 1000);
} else {
// For other file types, trigger download
handleDownload(e);
}
} catch (error) {
console.error('Error previewing attachment:', error);
alert(`Failed to preview attachment: ${error instanceof Error ? error.message : 'Unknown error'}`);
}
};
// Determine if file can be previewed
const contentType = attachment.contentType || '';
const isImage = contentType.startsWith('image/');
const isPDF = contentType === 'application/pdf';
const isText = contentType.startsWith('text/');
const canPreview = isImage || isPDF || isText;
return ( return (
<div <div
key={idx} key={idx}
className="flex items-center gap-2 p-2 border border-gray-200 rounded-md hover:bg-gray-50 transition-colors cursor-pointer" className="flex items-center gap-2 p-3 border border-gray-200 rounded-md hover:bg-gray-50 transition-colors"
onClick={handleDownload}
title={`Click to download ${attachment.filename}`}
> >
<div className="flex-1 min-w-0"> <div className="flex-1 min-w-0">
<p className="text-sm font-medium text-gray-700 truncate">{attachment.filename}</p> <p className="text-sm font-medium text-gray-700 truncate">{attachment.filename}</p>
<p className="text-xs text-gray-500">{(attachment.size / 1024).toFixed(1)} KB</p> <p className="text-xs text-gray-500">{(attachment.size / 1024).toFixed(1)} KB</p>
</div> </div>
<button <div className="flex items-center gap-1">
className="ml-2 p-1 text-gray-400 hover:text-blue-600 transition-colors" {canPreview && (
onClick={(e) => { <button
e.stopPropagation(); className="p-1.5 text-gray-400 hover:text-blue-600 transition-colors rounded"
handleDownload(e); onClick={handlePreview}
}} title="Preview attachment"
title="Download attachment" >
> <Eye className="w-4 h-4" />
<svg className="w-4 h-4" fill="none" stroke="currentColor" viewBox="0 0 24 24"> </button>
<path strokeLinecap="round" strokeLinejoin="round" strokeWidth={2} d="M4 16v1a3 3 0 003 3h10a3 3 0 003-3v-1m-4-4l-4 4m0 0l-4-4m4 4V4" /> )}
</svg> <button
</button> className="p-1.5 text-gray-400 hover:text-blue-600 transition-colors rounded"
onClick={handleDownload}
title="Download attachment"
>
<Download className="w-4 h-4" />
</button>
</div>
</div> </div>
); );
})} })}

View File

@ -1,7 +1,7 @@
'use client'; 'use client';
import React from 'react'; import React from 'react';
import { Star, Mail, MailOpen } from 'lucide-react'; import { Star, Mail, MailOpen, Paperclip } from 'lucide-react';
import { Checkbox } from '@/components/ui/checkbox'; import { Checkbox } from '@/components/ui/checkbox';
import { cn } from '@/lib/utils'; import { cn } from '@/lib/utils';
import { Email } from '@/hooks/use-courrier'; import { Email } from '@/hooks/use-courrier';
@ -188,9 +188,14 @@ export default function EmailListItem({
</div> </div>
</div> </div>
<h3 className="text-sm text-gray-900 truncate"> <div className="flex items-center gap-2">
{email.subject || '(No subject)'} <h3 className="text-sm text-gray-900 truncate flex-1">
</h3> {email.subject || '(No subject)'}
</h3>
{email.hasAttachments && (
<Paperclip className="h-3.5 w-3.5 text-gray-400 flex-shrink-0" title="Has attachments" />
)}
</div>
<div className="text-xs text-gray-500 truncate"> <div className="text-xs text-gray-500 truncate">
{getPreviewText(email.content)} {getPreviewText(email.content)}