From 5be6154065bdd520feb8d2db53adb2daadec67b9 Mon Sep 17 00:00:00 2001 From: Linus Rath <139418639+rathlinus@users.noreply.github.com> Date: Wed, 4 Nov 2026 06:04:44 +0100 Subject: [PATCH] fix: let the desktop notice about keeping mail on this device close by itself --- .../__tests__/offline-default-notice.test.tsx | 38 +++++++++++++++++++ components/offline/offline-host.tsx | 6 ++- 2 files changed, 43 insertions(+), 1 deletion(-) create mode 100644 components/offline/__tests__/offline-default-notice.test.tsx diff --git a/components/offline/__tests__/offline-default-notice.test.tsx b/components/offline/__tests__/offline-default-notice.test.tsx new file mode 100644 index 000000000..9d634869d --- /dev/null +++ b/components/offline/__tests__/offline-default-notice.test.tsx @@ -0,0 +1,38 @@ +import { cleanup, render } from '@testing-library/react'; +import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest'; +import type { OfflineNotice } from '@/lib/offline/offline-mode'; +import { useToastStore } from '@/stores/toast-store'; + +// mail-26: the desktop app's "Bulwark keeps your mail on this device" notice +// stayed over the quick reply box until someone closed it. + +const notifier = vi.hoisted(() => ({ show: null as ((notice: OfflineNotice) => void) | null })); +vi.mock('@/lib/offline/offline-mode', () => ({ + setOfflineNotifier: (fn: ((notice: OfflineNotice) => void) | null) => { + notifier.show = fn; + }, + startOfflineMode: () => () => {}, + confirmLoss: () => {}, + unsentCount: async () => ({ messages: 0, changes: 0 }), +})); + +const { OfflineHost } = await import('../offline-host'); + +beforeEach(() => { + useToastStore.getState().clearToasts(); +}); + +afterEach(() => { + cleanup(); +}); + +describe('the notice that the desktop app keeps mail on this device', () => { + it('goes away by itself, and still offers Settings', () => { + render(); + notifier.show!({ kind: 'default-on' }); + const [notice] = useToastStore.getState().toasts; + expect(notice.title).toBe('default_on'); + expect(notice.duration).toBeGreaterThan(0); + expect(notice.action?.label).toBe('open_settings'); + }); +}); diff --git a/components/offline/offline-host.tsx b/components/offline/offline-host.tsx index f86d066a3..643fc02ce 100644 --- a/components/offline/offline-host.tsx +++ b/components/offline/offline-host.tsx @@ -11,6 +11,9 @@ import { buildSettingsPath } from '@/lib/deep-links'; import { confirmLoss, setOfflineNotifier, startOfflineMode, unsentCount, type OfflineNotice } from '@/lib/offline/offline-mode'; import { toast } from '@/stores/toast-store'; +/** How long the notice that the desktop app keeps mail stays: a long sentence, so twice a plain toast. */ +const DEFAULT_ON_NOTICE_MS = 10_000; + /** * Runs offline mode (#523) in this tab: the JMAP client's offline hooks, * the outbox, the wipes. Its notices become toasts, and a sign-out the @@ -74,7 +77,8 @@ export function OfflineHost() { toast.warning(tStorageRef.current('storage_full_title'), { message: tStorageRef.current('storage_full_text'), duration: 0, action: openStorage }); break; case 'default-on': - toast.info(tStorageRef.current('default_on'), { duration: 0, action: openStorage }); + // Said once; it goes like other notices, and Settings has the switch. + toast.info(tStorageRef.current('default_on'), { duration: DEFAULT_ON_NOTICE_MS, action: openStorage }); break; case 'legacy-stranded': toast.warning(tConflictsRef.current('legacy_stranded'), { duration: 0 });