"use client"; import { formatDate } from "@/lib/utils"; import { Email, ThreadGroup } from "@/lib/jmap/types"; import { cn } from "@/lib/utils"; import { Avatar } from "@/components/ui/avatar"; import { Paperclip, Star, Circle, ChevronRight, ChevronDown, Loader2 } from "lucide-react"; import { useSettingsStore } from "@/stores/settings-store"; import { useUIStore } from "@/stores/ui-store"; import { getThreadColorTag } from "@/lib/thread-utils"; import { ThreadEmailItem } from "./thread-email-item"; interface ThreadListItemProps { thread: ThreadGroup; isExpanded: boolean; selectedEmailId?: string; isLoading?: boolean; expandedEmails?: Email[]; // Full thread emails when expanded onToggleExpand: () => void; onEmailSelect: (email: Email) => void; onContextMenu?: (e: React.MouseEvent, email: Email) => void; onOpenConversation?: (thread: ThreadGroup) => void; // Mobile: open full conversation view } // Color tag mapping const colorTags = { red: "bg-red-50 dark:bg-red-950/30", orange: "bg-orange-50 dark:bg-orange-950/30", yellow: "bg-yellow-50 dark:bg-yellow-950/30", green: "bg-green-50 dark:bg-green-950/30", blue: "bg-blue-50 dark:bg-blue-950/30", purple: "bg-purple-50 dark:bg-purple-950/30", pink: "bg-pink-50 dark:bg-pink-950/30", } as const; export function ThreadListItem({ thread, isExpanded, selectedEmailId, isLoading = false, expandedEmails, onToggleExpand, onEmailSelect, onContextMenu, onOpenConversation, }: ThreadListItemProps) { const showPreview = useSettingsStore((state) => state.showPreview); const isMobile = useUIStore((state) => state.isMobile); const { latestEmail, participantNames, hasUnread, hasStarred, hasAttachment, emailCount } = thread; // Get color tag from thread const threadColor = getThreadColorTag(thread.emails); const colorTag = threadColor ? colorTags[threadColor as keyof typeof colorTags] : null; // Check if latest email is selected const isSelected = selectedEmailId === latestEmail.id || thread.emails.some(e => e.id === selectedEmailId); // Single email thread - render as regular email, no expand if (emailCount === 1) { return ( onEmailSelect(latestEmail)} onContextMenu={onContextMenu} showPreview={showPreview} colorTag={colorTag} /> ); } // Get emails to display when expanded const emailsToShow = expandedEmails || thread.emails; const handleHeaderClick = (e: React.MouseEvent) => { // Mobile: open conversation view instead of inline expansion if (isMobile && onOpenConversation) { onOpenConversation(thread); return; } // Desktop: If clicking directly on the expand icon area, toggle expansion // Otherwise, select the latest email const target = e.target as HTMLElement; if (target.closest('[data-expand-toggle]')) { onToggleExpand(); } else { // Clicking on the row selects the latest email but also expands if (!isExpanded) { onToggleExpand(); } onEmailSelect(latestEmail); } }; const handleContextMenu = (e: React.MouseEvent) => { onContextMenu?.(e, latestEmail); }; return (
{/* Thread Header (collapsed view) */}
{/* Expand/Collapse Button - Hidden on mobile */} {!isMobile && ( )} {/* Unread indicator */} {hasUnread && (
)} {/* Avatar */} {/* Content */}
{/* First Line: Participants and Date */}
{participantNames.join(", ")} {/* Email count badge */} {emailCount}
{hasStarred && ( )} {hasAttachment && ( )}
{formatDate(latestEmail.receivedAt)}
{/* Second Line: Subject */}
{latestEmail.subject || "(no subject)"}
{/* Third Line: Preview */} {showPreview && (

{latestEmail.preview || "No preview available"}

)}
{/* Expanded Thread Emails - Desktop only */} {isExpanded && !isMobile && (
{isLoading ? (
Loading conversation...
) : ( emailsToShow.map((email, index) => ( onEmailSelect(email)} onContextMenu={onContextMenu} /> )) )}
)}
); } // Single email item (for threads with only 1 email) function SingleEmailItem({ email, selected, onClick, onContextMenu, showPreview, colorTag, }: { email: Email; selected: boolean; onClick: () => void; onContextMenu?: (e: React.MouseEvent, email: Email) => void; showPreview: boolean; colorTag: string | null; }) { const isUnread = !email.keywords?.$seen; const isStarred = email.keywords?.$flagged; const sender = email.from?.[0]; const handleContextMenu = (e: React.MouseEvent) => { onContextMenu?.(e, email); }; return (
{/* Spacer for alignment with thread items */}
{/* Unread indicator */} {isUnread && (
)} {/* Avatar */} {/* Content */}
{/* First Line: Sender and Date */}
{sender?.name || sender?.email || "Unknown"}
{isStarred && ( )} {email.hasAttachment && ( )}
{formatDate(email.receivedAt)}
{/* Second Line: Subject */}
{email.subject || "(no subject)"}
{/* Third Line: Preview */} {showPreview && (

{email.preview || "No preview available"}

)}
); }