- Add ui/src/api/push.ts with getVapidPublicKey, subscribe, unsubscribe methods - Add ui/src/hooks/usePushNotifications.ts with SW pushManager subscription flow - urlBase64ToUint8Array utility converts VAPID key for applicationServerKey - NotificationPermissionPrompt shows after 3rd agent response (engagement gate) - Checks nexus.notifPromptDismissed localStorage key for dismiss state - ChatPanel tracks agentResponseCount from assistant messages and renders prompt - Install idb package (missing dependency from plan 26-00 prerequisites)
28 lines
933 B
TypeScript
28 lines
933 B
TypeScript
import { api } from "./client";
|
|
|
|
export const pushApi = {
|
|
getVapidPublicKey(): Promise<{ publicKey: string | null }> {
|
|
return api.get<{ publicKey: string | null }>("/push/vapid-public-key");
|
|
},
|
|
|
|
subscribe(
|
|
subscription: ReturnType<PushSubscription["toJSON"]>,
|
|
meta?: { userId?: string; companyId?: string; deviceLabel?: string },
|
|
): Promise<void> {
|
|
return api.post<void>("/push/subscribe", { ...subscription, ...meta });
|
|
},
|
|
|
|
unsubscribe(endpoint: string): Promise<void> {
|
|
// DELETE with body requires a manual fetch since api.delete() doesn't support body
|
|
return fetch("/api/push/subscribe", {
|
|
method: "DELETE",
|
|
headers: { "Content-Type": "application/json" },
|
|
credentials: "include",
|
|
body: JSON.stringify({ endpoint }),
|
|
}).then((res) => {
|
|
if (!res.ok && res.status !== 204) {
|
|
throw new Error(`Unsubscribe failed: ${res.status}`);
|
|
}
|
|
});
|
|
},
|
|
};
|