bulk-actions-bar.tsx7.2 KBView on GitHub import {
Archive,
Trash,
ArchiveX,
Mail as MailIcon,
MailOpen,
Star,
Inbox,
Zap,
X,
} from 'lucide-react';
import { BulkActionsLabelsPopover } from '@/modules/labels/components/bulk-actions-labels-popover';
import { useOptimisticActions } from '@/modules/threads/rendering/use-optimistic-actions';
import { Tooltip, TooltipContent, TooltipTrigger } from '@/components/ui/tooltip';
import { useMailActions } from '@/modules/store';
import { Button } from '@/components/ui/button';
import { m } from '@/paraglide/messages';
import { useCallback } from 'react';
interface BulkActionsBarProps {
selectedThreadIds: string[];
currentFolder: string;
onExitSelection: () => void;
}
export function BulkActionsBar({
selectedThreadIds,
currentFolder,
onExitSelection,
}: BulkActionsBarProps) {
const {
optimisticMarkAsRead,
optimisticMarkAsUnread,
optimisticToggleStar,
optimisticMoveThreadsTo,
optimisticDeleteThreads,
optimisticToggleImportant,
} = useOptimisticActions();
const { clearBulkSelection } = useMailActions();
// Determine which actions are available based on current folder
const isInbox = currentFolder === 'inbox';
const isSpam = currentFolder === 'spam';
const isBin = currentFolder === 'bin' || currentFolder === 'trash';
const isArchive = currentFolder === 'archive';
const isSent = currentFolder === 'sent';
const handleMarkAsRead = useCallback(() => {
optimisticMarkAsRead(selectedThreadIds);
clearBulkSelection();
}, [optimisticMarkAsRead, selectedThreadIds, clearBulkSelection]);
const handleMarkAsUnread = useCallback(() => {
optimisticMarkAsUnread(selectedThreadIds);
clearBulkSelection();
}, [optimisticMarkAsUnread, selectedThreadIds, clearBulkSelection]);
const handleArchive = useCallback(() => {
optimisticMoveThreadsTo(selectedThreadIds, currentFolder, 'archive');
clearBulkSelection();
}, [optimisticMoveThreadsTo, selectedThreadIds, currentFolder, clearBulkSelection]);
const handleMoveToInbox = useCallback(() => {
optimisticMoveThreadsTo(selectedThreadIds, currentFolder, 'inbox');
clearBulkSelection();
}, [optimisticMoveThreadsTo, selectedThreadIds, currentFolder, clearBulkSelection]);
const handleMoveToSpam = useCallback(() => {
optimisticMoveThreadsTo(selectedThreadIds, currentFolder, 'spam');
clearBulkSelection();
}, [optimisticMoveThreadsTo, selectedThreadIds, currentFolder, clearBulkSelection]);
const handleDelete = useCallback(() => {
// Use optimisticDeleteThreads which calls the proper bulkDelete endpoint
// This will remove INBOX, SPAM, and SENT labels and add TRASH
optimisticDeleteThreads(selectedThreadIds);
clearBulkSelection();
}, [optimisticDeleteThreads, selectedThreadIds, clearBulkSelection]);
const handleStar = useCallback(() => {
optimisticToggleStar(selectedThreadIds, true);
clearBulkSelection();
}, [optimisticToggleStar, selectedThreadIds, clearBulkSelection]);
const handleMarkImportant = useCallback(() => {
optimisticToggleImportant(selectedThreadIds, true);
clearBulkSelection();
}, [optimisticToggleImportant, selectedThreadIds, clearBulkSelection]);
return (
<div className="flex flex-1 items-center justify-between gap-2">
{/* Left side: Count and actions */}
<div className="flex items-center gap-2">
<div className="text-foreground text-sm font-medium">
{selectedThreadIds.length} selected
</div>
{/* Mark as Read/Unread */}
<Tooltip>
<TooltipTrigger asChild>
<Button variant="ghost" size="sm" onClick={handleMarkAsRead} className="h-8 w-8 p-0">
<MailOpen className="h-4 w-4" />
</Button>
</TooltipTrigger>
<TooltipContent>Mark as read</TooltipContent>
</Tooltip>
<Tooltip>
<TooltipTrigger asChild>
<Button variant="ghost" size="sm" onClick={handleMarkAsUnread} className="h-8 w-8 p-0">
<MailIcon className="h-4 w-4" />
</Button>
</TooltipTrigger>
<TooltipContent>Mark as unread</TooltipContent>
</Tooltip>
{/* Star */}
<Tooltip>
<TooltipTrigger asChild>
<Button variant="ghost" size="sm" onClick={handleStar} className="h-8 w-8 p-0">
<Star className="h-4 w-4" />
</Button>
</TooltipTrigger>
<TooltipContent>Add to favorites</TooltipContent>
</Tooltip>
{/* Mark Important */}
<Tooltip>
<TooltipTrigger asChild>
<Button variant="ghost" size="sm" onClick={handleMarkImportant} className="h-8 w-8 p-0">
<Zap className="h-4 w-4" />
</Button>
</TooltipTrigger>
<TooltipContent>Mark as important</TooltipContent>
</Tooltip>
{/* Divider */}
<div className="bg-border h-6 w-px" />
{/* Archive (only show in inbox or sent) */}
{(isInbox || isSent) && (
<Tooltip>
<TooltipTrigger asChild>
<Button variant="ghost" size="sm" onClick={handleArchive} className="h-8 w-8 p-0">
<Archive className="h-4 w-4" />
</Button>
</TooltipTrigger>
<TooltipContent>Archive</TooltipContent>
</Tooltip>
)}
{/* Move to Inbox (only show in archive, spam, or bin) */}
{(isArchive || isSpam || isBin) && (
<Tooltip>
<TooltipTrigger asChild>
<Button variant="ghost" size="sm" onClick={handleMoveToInbox} className="h-8 w-8 p-0">
<Inbox className="h-4 w-4" />
</Button>
</TooltipTrigger>
<TooltipContent>Move to inbox</TooltipContent>
</Tooltip>
)}
{/* Move to Spam (only show in inbox) */}
{isInbox && (
<Tooltip>
<TooltipTrigger asChild>
<Button variant="ghost" size="sm" onClick={handleMoveToSpam} className="h-8 w-8 p-0">
<ArchiveX className="h-4 w-4" />
</Button>
</TooltipTrigger>
<TooltipContent>Move to spam</TooltipContent>
</Tooltip>
)}
{/* Delete */}
<Tooltip>
<TooltipTrigger asChild>
<Button variant="ghost" size="sm" onClick={handleDelete} className="h-8 w-8 p-0">
<Trash className="h-4 w-4" />
</Button>
</TooltipTrigger>
<TooltipContent>Move to trash</TooltipContent>
</Tooltip>
{/* Divider */}
<div className="bg-border h-6 w-px" />
{/* Labels Popover */}
<BulkActionsLabelsPopover
selectedThreadIds={selectedThreadIds}
onComplete={clearBulkSelection}
/>
</div>
{/* Right side: Exit button */}
<Tooltip>
<TooltipTrigger asChild>
<Button
variant="secondary"
size="sm"
onClick={onExitSelection}
className="h-8 gap-2 rounded-lg"
>
<X className="h-3 w-3" />
<span className="text-xs">ESC</span>
</Button>
</TooltipTrigger>
<TooltipContent>{m['common.actions.exitSelectionModeEsc']()}</TooltipContent>
</Tooltip>
</div>
);
}