1import type { DesktopBridge, DesktopUpdateState } from "@t3tools/contracts";
2import { ArrowRightIcon } from "lucide-react";
3
4import {
5 getDesktopUpdateDownloadedVersion,
6 getDesktopUpdateReleaseUrl,
7} from "./desktopUpdate.logic";
8import { toastManager } from "./ui/toast";
9
10type DesktopUpdateShell = Pick<DesktopBridge, "openExternal">;
11
12export async function openDesktopUpdateReleaseNotes(
13 shell: DesktopUpdateShell | undefined,
14 releaseUrl: string,
15): Promise<void> {
16 try {
17 if (shell && (await shell.openExternal(releaseUrl))) return;
18 } catch {
19 // Surface rejected IPC calls through the same user-visible fallback.
20 }
21 toastManager.add({ type: "error", title: "Unable to open release notes" });
22}
23
24function ReleaseNotesLink({
25 shell,
26 releaseUrl,
27}: {
28 shell: DesktopUpdateShell;
29 releaseUrl: string;
30}) {
31 return (
32 <button
33 className="ml-2 inline cursor-pointer text-muted-foreground underline decoration-dotted underline-offset-4 transition-colors hover:text-foreground"
34 onClick={() => {
35 void openDesktopUpdateReleaseNotes(shell, releaseUrl);
36 }}
37 type="button"
38 >
39 Read more
40 <ArrowRightIcon
41 aria-hidden
42 className="ml-1 inline size-3 -rotate-45 align-[-0.125em]"
43 strokeWidth={2.25}
44 />
45 </button>
46 );
47}
48
49export function showDesktopUpdateDownloadedToast(
50 shell: DesktopUpdateShell,
51 state: DesktopUpdateState,
52): void {
53 const releaseUrl = getDesktopUpdateReleaseUrl(getDesktopUpdateDownloadedVersion(state));
54 toastManager.add({
55 type: "success",
56 title: "Update downloaded",
57 description: (
58 <>
59 {state.installKind === "ui"
60 ? "Reload the UI from the update button to apply it."
61 : "Restart the app from the update button to install it."}
62 {releaseUrl ? <ReleaseNotesLink releaseUrl={releaseUrl} shell={shell} /> : null}
63 </>
64 ),
65 });
66}