From 5cf69591c57c1b72d7270f2963f0e912fba40f05 Mon Sep 17 00:00:00 2001 From: Milos Petrovic Date: Tue, 14 Jul 2026 12:46:46 +0200 Subject: [PATCH 1/2] Clips: Stop re-prompting users to download the desktop app --- .../app/components/library/library-layout.tsx | 2 +- .../clips/app/hooks/use-desktop-promo.ts | 18 +++++---------- .../app/lib/capture-install-options.test.ts | 22 ++++++++++++++++++- .../clips/app/lib/capture-install-options.ts | 21 ++++++++++++++++++ .../clips/app/routes/_app.meetings._index.tsx | 15 ------------- templates/clips/app/routes/download.tsx | 5 +++-- ...tay-hidden-after-you-download-the-insta.md | 6 +++++ 7 files changed, 58 insertions(+), 31 deletions(-) create mode 100644 templates/clips/changelog/2026-07-14-desktop-app-prompts-stay-hidden-after-you-download-the-insta.md diff --git a/templates/clips/app/components/library/library-layout.tsx b/templates/clips/app/components/library/library-layout.tsx index d4afc1f062..62384c6cf5 100644 --- a/templates/clips/app/components/library/library-layout.tsx +++ b/templates/clips/app/components/library/library-layout.tsx @@ -524,7 +524,7 @@ export function LibraryLayout({ children }: LibraryLayoutProps) { <>
{shouldShowSidebarLink && ( - + {t("navigation.desktopCta")} diff --git a/templates/clips/app/hooks/use-desktop-promo.ts b/templates/clips/app/hooks/use-desktop-promo.ts index 82ad06b317..45fb608278 100644 --- a/templates/clips/app/hooks/use-desktop-promo.ts +++ b/templates/clips/app/hooks/use-desktop-promo.ts @@ -1,8 +1,10 @@ import { useCallback, useEffect, useState } from "react"; import { useIsMobile } from "@/hooks/use-mobile"; - -const DISMISSED_KEY = "clips.desktop-promo.dismissed"; +import { + hasDownloadedDesktopApp, + markDesktopAppDownloaded, +} from "@/lib/capture-install-options"; function detectDesktopApp(): boolean { if (typeof navigator === "undefined") return false; @@ -25,20 +27,12 @@ export function useDesktopPromo() { useEffect(() => { setIsDesktopApp(detectDesktopApp()); - setDismissed( - typeof window !== "undefined" && - window.localStorage?.getItem(DISMISSED_KEY) === "1", - ); + setDismissed(hasDownloadedDesktopApp()); }, []); const dismiss = useCallback(() => { setDismissed(true); - try { - window.localStorage?.setItem(DISMISSED_KEY, "1"); - } catch { - // localStorage can throw in private browsing — ignore, dismissal - // still holds for the session via React state. - } + markDesktopAppDownloaded(); }, []); return { diff --git a/templates/clips/app/lib/capture-install-options.test.ts b/templates/clips/app/lib/capture-install-options.test.ts index 989d309c67..e964dd65c8 100644 --- a/templates/clips/app/lib/capture-install-options.test.ts +++ b/templates/clips/app/lib/capture-install-options.test.ts @@ -1,11 +1,31 @@ -import { describe, expect, it } from "vitest"; +import { afterEach, describe, expect, it, vi } from "vitest"; import { + hasDownloadedDesktopApp, + markDesktopAppDownloaded, resolveClipsChromeExtensionEnabled, supportsPublishedClipsChromeExtensionHost, } from "./capture-install-options"; describe("capture install options", () => { + afterEach(() => { + vi.unstubAllGlobals(); + }); + + it("remembers when the desktop installer is downloaded", () => { + const values = new Map(); + vi.stubGlobal("window", { + localStorage: { + getItem: (key: string) => values.get(key) ?? null, + setItem: (key: string, value: string) => values.set(key, value), + }, + }); + + expect(hasDownloadedDesktopApp()).toBe(false); + markDesktopAppDownloaded(); + expect(hasDownloadedDesktopApp()).toBe(true); + }); + it("enables the published Chrome extension on supported first-party/local hosts", () => { expect( supportsPublishedClipsChromeExtensionHost("clips.agent-native.com"), diff --git a/templates/clips/app/lib/capture-install-options.ts b/templates/clips/app/lib/capture-install-options.ts index 01870d5e81..a8315afa8d 100644 --- a/templates/clips/app/lib/capture-install-options.ts +++ b/templates/clips/app/lib/capture-install-options.ts @@ -1,3 +1,24 @@ +const DESKTOP_DOWNLOAD_STORAGE_KEY = "clips.desktop-promo.dismissed"; + +export function hasDownloadedDesktopApp(): boolean { + try { + return ( + typeof window !== "undefined" && + window.localStorage?.getItem(DESKTOP_DOWNLOAD_STORAGE_KEY) === "1" + ); + } catch { + return false; + } +} + +export function markDesktopAppDownloaded(): void { + try { + window.localStorage?.setItem(DESKTOP_DOWNLOAD_STORAGE_KEY, "1"); + } catch { + // Download tracking is best-effort and must not block the installer. + } +} + function isFalsy(value: unknown): boolean { if (typeof value !== "string") return false; return ["0", "false", "no", "off"].includes(value.trim().toLowerCase()); diff --git a/templates/clips/app/routes/_app.meetings._index.tsx b/templates/clips/app/routes/_app.meetings._index.tsx index 15c35af7bd..97bfd63e04 100644 --- a/templates/clips/app/routes/_app.meetings._index.tsx +++ b/templates/clips/app/routes/_app.meetings._index.tsx @@ -748,21 +748,6 @@ function MeetingsHeader({ )}
- {showDesktopCta && ( -
- - - {t("meetingsRoute.getDesktopApp")} - -

- {t("meetingsRoute.requiredForReminders")} -

-
- )} ); diff --git a/templates/clips/app/routes/download.tsx b/templates/clips/app/routes/download.tsx index df1dec45b2..fee1e8430a 100644 --- a/templates/clips/app/routes/download.tsx +++ b/templates/clips/app/routes/download.tsx @@ -14,6 +14,7 @@ import enMessages from "@/i18n/en-US"; import { clipsChromeExtensionEnabled, clipsChromeExtensionUrl, + markDesktopAppDownloaded, } from "@/lib/capture-install-options"; export function meta() { @@ -118,7 +119,7 @@ function primaryDownloadButton( if (asset) { return (