Unified · Split
| @@ -8,41 +8,6 @@ import { useSession } from "@/lib/session-context"; · 7 unmodified lines | ||
| 8 | 8 | import { convexApi } from "@/lib/convex-api"; |
| 9 | 9 | import type { PendingApprovalRecord } from "@/lib/types"; |
| 10 | 10 | |
| 11 | −const NOTIFICATION_PROMPT_KEY = "executor_approval_desktop_notifications_prompted_v1"; | |
| 12 | − | |
| 13 | −function supportsDesktopNotifications(): boolean { | |
| 14 | − return typeof window !== "undefined" && "Notification" in window; | |
| 15 | −} | |
| 16 | − | |
| 17 | −function notifyDesktop(approval: PendingApprovalRecord) { | |
| 18 | − if (!supportsDesktopNotifications()) { | |
| 19 | − return; | |
| 20 | − } | |
| 21 | − | |
| 22 | − if (Notification.permission !== "granted") { | |
| 23 | − return; | |
| 24 | − } | |
| 25 | − | |
| 26 | − if (document.visibilityState === "visible") { | |
| 27 | − return; | |
| 28 | − } | |
| 29 | − | |
| 30 | − const notification = new Notification("Approval required", { | |
| 31 | − body: `${approval.toolPath} is waiting for review`, | |
| 32 | − tag: `approval-${approval.id}`, | |
| 33 | − }); | |
| 34 | − | |
| 35 | − notification.onclick = () => { | |
| 36 | − window.focus(); | |
| 37 | − window.location.assign("/approvals"); | |
| 38 | − notification.close(); | |
| 39 | − }; | |
| 40 | − | |
| 41 | − window.setTimeout(() => { | |
| 42 | − notification.close(); | |
| 43 | − }, 12_000); | |
| 44 | −} | |
| 45 | − | |
| 46 | 11 | export function ApprovalNotifier() { |
| 47 | 12 | const router = useRouter(); |
| 48 | 13 | const { context } = useSession(); |
| @@ -98,59 +63,7 @@ export function ApprovalNotifier() { · 49 unmodified lines | ||
| 98 | 63 | }, |
| 99 | 64 | ); |
| 100 | 65 | |
| 101 | − for (const approval of newApprovals) { | |
| 102 | − notifyDesktop(approval); | |
| 103 | − } | |
| 104 | 66 | }, [approvals, context, router]); |
| 105 | 67 | |
| 106 | − useEffect(() => { | |
| 107 | − if (!context) { | |
| 108 | − return; | |
| 109 | − } | |
| 110 | − | |
| 111 | − if (!supportsDesktopNotifications()) { | |
| 112 | − return; | |
| 113 | − } | |
| 114 | − | |
| 115 | − if (Notification.permission !== "default") { | |
| 116 | − return; | |
| 117 | − } | |
| 118 | − | |
| 119 | − if (localStorage.getItem(NOTIFICATION_PROMPT_KEY)) { | |
| 120 | − return; | |
| 121 | − } | |
| 122 | − | |
| 123 | − localStorage.setItem(NOTIFICATION_PROMPT_KEY, "1"); | |
| 124 | − | |
| 125 | − toast.message("Enable desktop approval alerts?", { | |
| 126 | − description: "Get browser notifications when new approvals arrive.", | |
| 127 | − duration: 14_000, | |
| 128 | − action: { | |
| 129 | − label: "Enable", | |
| 130 | − onClick: async () => { | |
| 131 | − if (!supportsDesktopNotifications()) { | |
| 132 | − return; | |
| 133 | − } | |
| 134 | − | |
| 135 | − try { | |
| 136 | − const permission = await Notification.requestPermission(); | |
| 137 | − | |
| 138 | − if (permission === "granted") { | |
| 139 | − toast.success("Desktop notifications enabled"); | |
| 140 | − } else if (permission === "denied") { | |
| 141 | − toast.error("Desktop notifications blocked in this browser"); | |
| 142 | − } | |
| 143 | − } catch { | |
| 144 | − toast.error("Failed to request notification permission"); | |
| 145 | − } | |
| 146 | − }, | |
| 147 | − }, | |
| 148 | − cancel: { | |
| 149 | − label: "Later", | |
| 150 | − onClick: () => {}, | |
| 151 | − }, | |
| 152 | − }); | |
| 153 | − }, [context]); | |
| 154 | − | |
| 155 | 68 | return null; |
| 156 | 69 | } |