mirror of
https://github.com/bulwarkmail/webmail.git
synced 2026-11-05 00:14:18 +00:00
X, Escape, clicking another message and Escape in a pop-out window now all save the draft and close, with a "Draft saved" toast that has Discard (with Undo). The Save or discard question shows only when that save fails. A Reply or Forward closed before the user changed anything leaves no draft. Undo send being on by default no longer asks "Send without a delay?" on servers without delayed sending; only a delay the user picked does. Changed test assertions: the close-guard, priority, account-switch, threading, sign-out, mention, draft-attachments, discard-uploads and save-pending-attachments tests reached saving or discarding through the Save or discard dialog on close, which now only appears after a failed save. They now close directly, or use the Discard button, or check the failed-save question. The send-delay test marks its delay as chosen.
57 lines
1.9 KiB
TypeScript
57 lines
1.9 KiB
TypeScript
import { toast, useToastStore } from "@/stores/toast-store";
|
|
import { UNDO_TOAST_DURATION } from "@/lib/email-action-toast";
|
|
|
|
export interface DiscardToastLabels {
|
|
discarded: string;
|
|
undo: string;
|
|
}
|
|
|
|
export interface DraftSavedToastLabels extends DiscardToastLabels {
|
|
saved: string;
|
|
discard: string;
|
|
}
|
|
|
|
/**
|
|
* "Draft discarded" with Undo. `discard` runs once the toast is gone without
|
|
* an Undo (or the page goes away), so Undo needs nothing from the server:
|
|
* the draft is still there. `restore` puts back what the caller took off
|
|
* screen.
|
|
*/
|
|
export function discardWithUndo(discard: () => void, labels: DiscardToastLabels, restore?: () => void): void {
|
|
let settled = false;
|
|
let timer: ReturnType<typeof setTimeout> | null = null;
|
|
const commit = () => {
|
|
if (settled) return;
|
|
settled = true;
|
|
if (timer) clearTimeout(timer);
|
|
window.removeEventListener("pagehide", commit);
|
|
discard();
|
|
};
|
|
const id = toast.success(labels.discarded, {
|
|
action: {
|
|
label: labels.undo,
|
|
onClick: () => {
|
|
if (settled) return;
|
|
settled = true;
|
|
if (timer) clearTimeout(timer);
|
|
window.removeEventListener("pagehide", commit);
|
|
restore?.();
|
|
},
|
|
},
|
|
duration: UNDO_TOAST_DURATION,
|
|
// The toast and the delete end together: a pause on hover would leave
|
|
// an Undo on screen for a draft that is already gone.
|
|
pauseOnHover: false,
|
|
});
|
|
const shown = useToastStore.getState().toasts.find((t) => t.id === id)?.duration;
|
|
timer = setTimeout(commit, shown && shown > 0 ? shown : UNDO_TOAST_DURATION);
|
|
window.addEventListener("pagehide", commit);
|
|
}
|
|
|
|
/** After a composer closed and kept its draft: "Draft saved", with Discard. */
|
|
export function showDraftSavedToast(discard: () => void, labels: DraftSavedToastLabels): void {
|
|
toast.success(labels.saved, {
|
|
action: { label: labels.discard, onClick: () => discardWithUndo(discard, labels) },
|
|
});
|
|
}
|