diff --git a/app/(main)/[locale]/page.tsx b/app/(main)/[locale]/page.tsx index 464b795c..0db35bc3 100644 --- a/app/(main)/[locale]/page.tsx +++ b/app/(main)/[locale]/page.tsx @@ -1428,6 +1428,27 @@ export default function Home() { toast.success(t('email_viewer.scheduled_send_created'), { duration: undoDurationMs, + secondaryAction: (pending.emailId && pending.identityId) + ? { + label: t('email_viewer.send_now'), + onClick: () => { + void (async () => { + try { + await client.rescheduleEmailSubmission( + pending.submissionId, + pending.emailId!, + pending.identityId!, + new Date(Date.now() + 1000).toISOString(), + ); + clearPendingUndoSend(); + if (isScheduledView) await fetchScheduledEmails(client); + } catch (error) { + console.error('Failed to send now:', error); + } + })(); + }, + } + : undefined, action: { label: t('email_viewer.undo_send'), onClick: () => { diff --git a/components/ui/toast.tsx b/components/ui/toast.tsx index 9e55dc92..25ffe56e 100644 --- a/components/ui/toast.tsx +++ b/components/ui/toast.tsx @@ -21,6 +21,7 @@ export interface Toast { onClick?: () => void; icon?: React.ReactNode; action?: ToastAction; + secondaryAction?: ToastAction; } interface ToastProps { @@ -117,25 +118,48 @@ export function ToastItem({ toast, onClose }: ToastProps) { {toast.message && (

{toast.message}

)} - {toast.action && ( - )} - > - {toast.action.label} - + {toast.action && ( + + )} + )} diff --git a/stores/email-store.ts b/stores/email-store.ts index 33d13867..6ee083cf 100644 --- a/stores/email-store.ts +++ b/stores/email-store.ts @@ -20,7 +20,7 @@ type ScheduledSubmissionMetadata = { const VIRTUAL_SCHEDULED_MAILBOX_ID = '__scheduled__'; -type PendingUndoSend = { submissionId: string; emailId?: string; sendAt: string; isSmime: boolean }; +type PendingUndoSend = { submissionId: string; emailId?: string; identityId?: string; sendAt: string; isSmime: boolean }; interface EmailStore { emails: Email[]; @@ -1287,7 +1287,7 @@ export const useEmailStore = create((set, get) => ({ set({ isLoading: false, pendingUndoSend: result.scheduled && result.emailSubmissionId && result.sendAt - ? { submissionId: result.emailSubmissionId, emailId: result.emailId, sendAt: result.sendAt, isSmime: false } + ? { submissionId: result.emailSubmissionId, emailId: result.emailId, identityId, sendAt: result.sendAt, isSmime: false } : get().pendingUndoSend, }); return result; @@ -1311,7 +1311,7 @@ export const useEmailStore = create((set, get) => ({ set({ isLoading: false, pendingUndoSend: result.scheduled && result.emailSubmissionId && result.sendAt - ? { submissionId: result.emailSubmissionId, emailId: result.emailId, sendAt: result.sendAt, isSmime: true } + ? { submissionId: result.emailSubmissionId, emailId: result.emailId, identityId, sendAt: result.sendAt, isSmime: true } : get().pendingUndoSend, }); return result; diff --git a/stores/toast-store.ts b/stores/toast-store.ts index 35e3e4aa..820e178a 100644 --- a/stores/toast-store.ts +++ b/stores/toast-store.ts @@ -38,6 +38,7 @@ export const useToastStore = create((set) => ({ interface ToastOptions { message?: string; action?: ToastAction; + secondaryAction?: ToastAction; duration?: number; } @@ -48,6 +49,7 @@ function showToast(type: Toast["type"], title: string, options?: string | ToastO title, message: opts?.message, action: opts?.action, + secondaryAction: opts?.secondaryAction, duration: opts?.duration ?? defaultDuration, }); }