Neah/components/email/EmailListItem.tsx
2025-04-26 23:06:39 +02:00

163 lines
4.6 KiB
TypeScript

'use client';
import React from 'react';
import { Star, Mail, MailOpen } from 'lucide-react';
import { Checkbox } from '@/components/ui/checkbox';
import { cn } from '@/lib/utils';
import { Email } from '@/hooks/use-courrier';
import { Badge } from '@/components/ui/badge';
import { Avatar, AvatarFallback } from '@/components/ui/avatar';
interface EmailListItemProps {
email: Email;
isSelected: boolean;
isActive: boolean;
onSelect: () => void;
onToggleSelect: (e: React.MouseEvent) => void;
onToggleStarred: (e: React.MouseEvent) => void;
}
export default function EmailListItem({
email,
isSelected,
isActive,
onSelect,
onToggleSelect,
onToggleStarred
}: EmailListItemProps) {
// Format the date in a readable way
const formatDate = (dateString: string) => {
const date = new Date(dateString);
const now = new Date();
const today = new Date(now.getFullYear(), now.getMonth(), now.getDate());
const yesterday = new Date(today);
yesterday.setDate(yesterday.getDate() - 1);
// Check if date is today
if (date >= today) {
return date.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' });
}
// Check if date is yesterday
if (date >= yesterday) {
return 'Yesterday';
}
// Check if date is this year
if (date.getFullYear() === now.getFullYear()) {
return date.toLocaleDateString([], { month: 'short', day: 'numeric' });
}
// Date is from a previous year
return date.toLocaleDateString([], { year: 'numeric', month: 'short', day: 'numeric' });
};
// Get the first letter of the sender's name or email for the avatar
const getSenderInitial = () => {
if (!email.from || email.from.length === 0) return '?';
const sender = email.from[0];
if (sender.name && sender.name.trim()) {
return sender.name.trim()[0].toUpperCase();
}
if (sender.address && sender.address.trim()) {
return sender.address.trim()[0].toUpperCase();
}
return '?';
};
// Get sender name or email
const getSenderName = () => {
if (!email.from || email.from.length === 0) return 'Unknown';
const sender = email.from[0];
if (sender.name && sender.name.trim()) {
return sender.name.trim();
}
return sender.address || 'Unknown';
};
// Generate a stable color based on the sender's email
const getAvatarColor = () => {
if (!email.from || email.from.length === 0) return 'hsl(0, 0%, 50%)';
const address = email.from[0].address || '';
let hash = 0;
for (let i = 0; i < address.length; i++) {
hash = address.charCodeAt(i) + ((hash << 5) - hash);
}
const h = hash % 360;
return `hsl(${h}, 70%, 80%)`;
};
// Get preview text from email content
const getPreviewText = () => {
if (email.preview) return email.preview;
let content = email.content || '';
// Strip HTML tags if present
content = content.replace(/<[^>]+>/g, ' ');
// Clean up whitespace
content = content.replace(/\s+/g, ' ').trim();
// Limit to ~70 chars
if (content.length > 70) {
return content.substring(0, 70) + '...';
}
return content || 'No preview available';
};
return (
<div
className={cn(
'flex items-center gap-3 px-4 py-2 hover:bg-gray-50/80 cursor-pointer',
isActive ? 'bg-blue-50/50' : '',
!email.read ? 'bg-blue-50/20' : ''
)}
onClick={onSelect}
>
<Checkbox
checked={isSelected}
onClick={onToggleSelect}
className="mt-0.5"
/>
<div className="flex-1 min-w-0">
<div className="flex items-center justify-between gap-2">
<div className="flex items-center gap-2 min-w-0">
<span className={`text-sm truncate ${!email.read ? 'font-semibold text-gray-900' : 'text-gray-600'}`}>
{getSenderName()}
</span>
</div>
<div className="flex items-center gap-2 flex-shrink-0">
<span className="text-xs text-gray-500 whitespace-nowrap">
{formatDate(email.date)}
</span>
<button
className="h-6 w-6 text-gray-400 hover:text-yellow-400"
onClick={onToggleStarred}
>
<Star className={`h-4 w-4 ${email.starred ? 'fill-yellow-400 text-yellow-400' : ''}`} />
</button>
</div>
</div>
<h3 className="text-sm text-gray-900 truncate">
{email.subject || '(No subject)'}
</h3>
<div className="text-xs text-gray-500 truncate">
{getPreviewText()}
</div>
</div>
</div>
);
}