"use client"; import { useTranslations } from "next-intl"; import { Mailbox } from "@/lib/jmap/types"; import { getMailboxPath } from "@/lib/utils"; import { ContextMenu, ContextMenuItem, ContextMenuSeparator, ContextMenuHeader, } from "@/components/ui/context-menu"; import { CheckCheck, ChevronRight, MailOpen, Mails, MoreHorizontal, Trash2, FolderPlus, Pencil, FolderX, RefreshCw, Upload, } from "lucide-react"; interface Position { x: number; y: number; } export type MailboxContextTarget = | { kind: "mailbox"; mailbox: Mailbox; hasChildren: boolean } | { kind: "folders-section" }; const PATH_SEPARATOR = " › "; const MAX_PATH_LENGTH = 40; const MAX_SEGMENT_LENGTH = 16; function truncateSegment(name: string): string { return name.length > MAX_SEGMENT_LENGTH ? `${name.slice(0, MAX_SEGMENT_LENGTH - 1)}…` : name; } function renderPathSegments(segments: string[]): React.ReactNode { return ( {segments.map((seg, i) => ( {i > 0 && } {seg === "…" ? : {seg}} ))} ); } function renderShortenedPath(fullPath: string): React.ReactNode { const segments = fullPath.split(PATH_SEPARATOR); if (fullPath.length <= MAX_PATH_LENGTH) { return renderPathSegments(segments); } if (segments.length <= 2) { return renderPathSegments(segments.map(truncateSegment)); } return renderPathSegments([ truncateSegment(segments[0]), "…", truncateSegment(segments[segments.length - 1]), ]); } interface MailboxContextMenuProps { target: MailboxContextTarget | null; position: Position; isOpen: boolean; onClose: () => void; menuRef: React.RefObject; mailboxes: Mailbox[]; onMarkFolderRead?: (mailboxId: string) => void; onMarkFolderTreeRead?: (mailboxId: string) => void; onMarkAllFoldersRead?: () => void; onEmptyFolder?: (mailboxId: string) => void; onCreateSubfolder?: (parentId: string) => void; onCreateFolder?: () => void; onRenameFolder?: (mailboxId: string) => void; onDeleteFolder?: (mailboxId: string) => void; onImportEmail?: (mailboxId: string) => void; onRefresh?: () => void; } export function MailboxContextMenu({ target, position, isOpen, onClose, menuRef, mailboxes, onMarkFolderRead, onMarkFolderTreeRead, onMarkAllFoldersRead, onEmptyFolder, onCreateSubfolder, onCreateFolder, onRenameFolder, onDeleteFolder, onImportEmail, onRefresh, }: MailboxContextMenuProps) { const t = useTranslations("mailbox_context_menu"); const handleAction = (action: () => void) => { action(); onClose(); }; if (!target) return null; if (target.kind === "folders-section") { return ( handleAction(onMarkAllFoldersRead!)} disabled={!onMarkAllFoldersRead} /> handleAction(onCreateFolder!)} disabled={!onCreateFolder} /> handleAction(onRefresh!)} disabled={!onRefresh} /> ); } const mailbox = target.mailbox; const isTrashOrJunk = mailbox.role === "trash" || mailbox.role === "junk"; const isSystem = !!mailbox.role && ["inbox", "sent", "drafts", "trash", "junk", "archive"].includes(mailbox.role); const canRename = mailbox.myRights?.mayRename !== false && !isSystem; const canDelete = mailbox.myRights?.mayDelete !== false && !isSystem; const canCreateChild = mailbox.myRights?.mayCreateChild !== false; const canSetSeen = mailbox.myRights?.maySetSeen !== false; const canRemoveItems = mailbox.myRights?.mayRemoveItems !== false; const canAddItems = mailbox.myRights?.mayAddItems !== false; const fullPath = getMailboxPath(mailbox, mailboxes); return ( {renderShortenedPath(fullPath)} handleAction(() => onMarkFolderRead?.(mailbox.id))} disabled={!onMarkFolderRead || !canSetSeen} /> {target.hasChildren && ( handleAction(() => onMarkFolderTreeRead?.(mailbox.id))} disabled={!onMarkFolderTreeRead || !canSetSeen} /> )} handleAction(() => onCreateSubfolder?.(mailbox.id))} disabled={!onCreateSubfolder || !canCreateChild} /> handleAction(() => onRenameFolder?.(mailbox.id))} disabled={!onRenameFolder || !canRename} /> handleAction(() => onImportEmail?.(mailbox.id))} disabled={!onImportEmail || !canAddItems} /> handleAction(() => onEmptyFolder?.(mailbox.id))} disabled={!onEmptyFolder || mailbox.totalEmails === 0 || !canRemoveItems} destructive /> handleAction(() => onDeleteFolder?.(mailbox.id))} disabled={!onDeleteFolder || !canDelete} destructive /> handleAction(onRefresh!)} disabled={!onRefresh} /> ); }