import { useState } from 'react'; import { MailOpen, Mail, Star, Archive, Trash2 } from 'lucide-react'; import { BulkApi } from '../api/client.js'; import { Button, useToast, Dialog, DialogContent, DialogHeader, DialogTitle, DialogDescription, DialogFooter, DialogClose, } from './ui'; /** * Toolbar shown above an email list when rows are selected. * * Safety (Phase 4 / UX-Critical): the destructive Trash action now requires an * explicit confirmation dialog, every action surfaces success/partial-failure via * a toast, and rows are only removed from the list when the server confirms the * whole batch succeeded (no more optimistic removal that hides failures). * `onDone(action, ids)` is called only on full success so the caller can prune state. */ export default function BulkToolbar({ selectedIds, onDone, onClear }) { const { toast } = useToast(); const [busy, setBusy] = useState(false); const [confirmTrash, setConfirmTrash] = useState(false); const count = selectedIds.length; if (count === 0) return null; const apply = async (fn, action, label) => { setBusy(true); try { const res = await fn(selectedIds); // CleanupResultDto: { succeededCount, failedCount, errors } const ok = res?.succeededCount ?? count; const failed = res?.failedCount ?? 0; if (failed > 0) { toast({ variant: 'warning', title: `${label}: ${ok} done, ${failed} failed`, description: 'Some items could not be updated — the list was left unchanged so you can retry.', }); } else { toast({ variant: 'success', title: `${label} ${ok} email${ok === 1 ? '' : 's'}` }); onDone(action, selectedIds); onClear(); } } catch { toast({ variant: 'danger', title: `Couldn't ${label.toLowerCase()} ${count} email${count === 1 ? '' : 's'}`, description: 'Please try again.' }); } finally { setBusy(false); setConfirmTrash(false); } }; return (
{count} selected
!busy && setConfirmTrash(o)}> Move {count} email{count === 1 ? '' : 's'} to Trash? This moves the selected mail to your Gmail Trash, where it stays recoverable for 30 days before Gmail permanently deletes it.
); }