diff --git a/apps/web/components/dashboard/email-editor-screen.test.tsx b/apps/web/components/dashboard/email-editor-screen.test.tsx index b3f3e12..c3e14a7 100644 --- a/apps/web/components/dashboard/email-editor-screen.test.tsx +++ b/apps/web/components/dashboard/email-editor-screen.test.tsx @@ -135,6 +135,51 @@ describe("EmailEditorScreen", () => { ).toBe(false); }); + it("doesn't ask to save again after a save made from an action", async () => { + Object.defineProperty(window.history, "length", { configurable: true, value: 2 }); + const onSave = mock().mockResolvedValue(undefined); + render( + ( + + )} + />, + ); + + fireEvent.click(screen.getByText("Change document")); + fireEvent.click(screen.getByRole("button", { name: "Send test" })); + await waitFor(() => expect(onSave).toHaveBeenCalledWith(mocks.changedContent)); + + fireEvent.click(screen.getByRole("button", { name: "Exit editor" })); + + expect(screen.queryByText("Save your changes?")).toBeNull(); + expect(mocks.back).toHaveBeenCalled(); + }); + + it("gives the unsaved-changes dialog room for its three actions", () => { + render( + , + ); + + fireEvent.click(screen.getByText("Change document")); + fireEvent.click(screen.getByRole("button", { name: "Exit editor" })); + + const dialog = screen.getByRole("alertdialog"); + expect(dialog.className).toContain("data-[size=default]:sm:max-w-lg"); + expect(dialog.className).not.toContain("data-[size=default]:sm:max-w-sm"); + }); + it("uses the fallback route for a deep-linked editor", () => { Object.defineProperty(window.history, "length", { configurable: true, diff --git a/apps/web/components/dashboard/email-editor-screen.tsx b/apps/web/components/dashboard/email-editor-screen.tsx index 6b30604..7a257eb 100644 --- a/apps/web/components/dashboard/email-editor-screen.tsx +++ b/apps/web/components/dashboard/email-editor-screen.tsx @@ -303,19 +303,30 @@ export function EmailEditorScreen({ } } + /** Persists the current document, throwing on failure. Every save goes + * through here, so a save from an action (such as a test send) also counts + * as saved for the unsaved-changes check. */ + async function persist() { + contentChanged.current = false; + try { + await onSave(contentRef.current); + } catch (err) { + contentChanged.current = true; + throw err; + } + } + /** Saves, returning whether it worked. */ async function save(): Promise { if (saving) return false; setSaving(true); setError(null); try { - contentChanged.current = false; - await onSave(contentRef.current); + await persist(); setSaved(true); setTimeout(() => setSaved(false), 2000); return true; } catch (err) { - contentChanged.current = true; setError(err instanceof ApiError ? err.message : "Failed to save email"); return false; } finally { @@ -337,7 +348,7 @@ export function EmailEditorScreen({
- {actions?.(() => onSave(contentRef.current))} + {actions?.(persist)}