Skip to content

Commit f047869

Browse files
committed
re-add context and sw after rebase
1 parent f729332 commit f047869

File tree

2 files changed

+146
-0
lines changed

2 files changed

+146
-0
lines changed
Lines changed: 110 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,110 @@
1+
import { API } from "api/api";
2+
import { buildInfo } from "api/queries/buildInfo";
3+
import { experiments } from "api/queries/experiments";
4+
import { useEmbeddedMetadata } from "hooks/useEmbeddedMetadata";
5+
import { useEffect, useState } from "react";
6+
import { useQuery } from "react-query";
7+
8+
interface WebpushNotifications {
9+
readonly enabled: boolean;
10+
readonly subscribed: boolean;
11+
readonly loading: boolean;
12+
13+
subscribe(): Promise<void>;
14+
unsubscribe(): Promise<void>;
15+
}
16+
17+
export const useWebpushNotifications = (): WebpushNotifications => {
18+
const { metadata } = useEmbeddedMetadata();
19+
const buildInfoQuery = useQuery(buildInfo(metadata["build-info"]));
20+
const enabledExperimentsQuery = useQuery(experiments(metadata.experiments));
21+
22+
const [subscribed, setSubscribed] = useState<boolean>(false);
23+
const [loading, setLoading] = useState<boolean>(true);
24+
const [enabled, setEnabled] = useState<boolean>(false);
25+
26+
useEffect(() => {
27+
// Check if the experiment is enabled.
28+
if (enabledExperimentsQuery.data?.includes("web-push")) {
29+
setEnabled(true);
30+
}
31+
32+
// Check if browser supports push notifications
33+
if (!("Notification" in window) || !("serviceWorker" in navigator)) {
34+
setSubscribed(false);
35+
setLoading(false);
36+
return;
37+
}
38+
39+
const checkSubscription = async () => {
40+
try {
41+
const registration = await navigator.serviceWorker.ready;
42+
const subscription = await registration.pushManager.getSubscription();
43+
setSubscribed(!!subscription);
44+
} catch (error) {
45+
console.error("Error checking push subscription:", error);
46+
setSubscribed(false);
47+
} finally {
48+
setLoading(false);
49+
}
50+
};
51+
52+
checkSubscription();
53+
}, [enabledExperimentsQuery.data]);
54+
55+
const subscribe = async (): Promise<void> => {
56+
try {
57+
setLoading(true);
58+
const registration = await navigator.serviceWorker.ready;
59+
const vapidPublicKey = buildInfoQuery.data?.webpush_public_key;
60+
61+
const subscription = await registration.pushManager.subscribe({
62+
userVisibleOnly: true,
63+
applicationServerKey: vapidPublicKey,
64+
});
65+
const json = subscription.toJSON();
66+
if (!json.keys || !json.endpoint) {
67+
throw new Error("No keys or endpoint found");
68+
}
69+
70+
await API.createNotificationPushSubscription("me", {
71+
endpoint: json.endpoint,
72+
auth_key: json.keys.auth,
73+
p256dh_key: json.keys.p256dh,
74+
});
75+
76+
setSubscribed(true);
77+
} catch (error) {
78+
console.error("Subscription failed:", error);
79+
throw error;
80+
} finally {
81+
setLoading(false);
82+
}
83+
};
84+
85+
const unsubscribe = async (): Promise<void> => {
86+
try {
87+
setLoading(true);
88+
const registration = await navigator.serviceWorker.ready;
89+
const subscription = await registration.pushManager.getSubscription();
90+
91+
if (subscription) {
92+
await subscription.unsubscribe();
93+
setSubscribed(false);
94+
}
95+
} catch (error) {
96+
console.error("Unsubscription failed:", error);
97+
throw error;
98+
} finally {
99+
setLoading(false);
100+
}
101+
};
102+
103+
return {
104+
subscribed,
105+
enabled,
106+
loading: loading || buildInfoQuery.isLoading,
107+
subscribe,
108+
unsubscribe,
109+
};
110+
};

site/src/serviceWorker.ts

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,36 @@
1+
/// <reference lib="webworker" />
2+
3+
import type { WebpushMessage } from "api/typesGenerated";
4+
5+
// @ts-ignore
6+
declare const self: ServiceWorkerGlobalScope;
7+
8+
self.addEventListener("install", (event) => {
9+
self.skipWaiting();
10+
});
11+
12+
self.addEventListener("activate", (event) => {
13+
event.waitUntil(self.clients.claim());
14+
});
15+
16+
self.addEventListener("push", (event) => {
17+
let payload: WebpushMessage;
18+
try {
19+
payload = event.data?.json();
20+
} catch (e) {
21+
console.error("Error parsing push payload:", e);
22+
return;
23+
}
24+
25+
event.waitUntil(
26+
self.registration.showNotification(payload.title, {
27+
body: payload.body || "",
28+
icon: payload.icon || "/favicon.ico",
29+
}),
30+
);
31+
});
32+
33+
// Handle notification click
34+
self.addEventListener("notificationclick", (event) => {
35+
event.notification.close();
36+
});

0 commit comments

Comments
 (0)