web: add firebase push token registration and sync
This commit is contained in:
109
web/src/utils/firebasePush.ts
Normal file
109
web/src/utils/firebasePush.ts
Normal file
@@ -0,0 +1,109 @@
|
||||
import { initializeApp, getApps } from "firebase/app";
|
||||
import { getMessaging, getToken, isSupported, onMessage, type MessagePayload } from "firebase/messaging";
|
||||
import { deletePushToken, upsertPushToken } from "../api/notifications";
|
||||
import { showNotificationViaServiceWorker } from "./webNotifications";
|
||||
|
||||
const WEB_PUSH_TOKEN_KEY = "bm_web_push_token";
|
||||
|
||||
let foregroundListenerAttached = false;
|
||||
|
||||
export async function ensureWebPushRegistration(): Promise<void> {
|
||||
const config = getFirebaseConfig();
|
||||
const vapidKey = import.meta.env.VITE_FIREBASE_VAPID_KEY?.trim();
|
||||
if (!config || !vapidKey) {
|
||||
return;
|
||||
}
|
||||
if (!(await isSupported())) {
|
||||
return;
|
||||
}
|
||||
if (!("Notification" in window)) {
|
||||
return;
|
||||
}
|
||||
if (Notification.permission === "default") {
|
||||
await Notification.requestPermission();
|
||||
}
|
||||
if (Notification.permission !== "granted") {
|
||||
return;
|
||||
}
|
||||
|
||||
if (!("serviceWorker" in navigator)) {
|
||||
return;
|
||||
}
|
||||
|
||||
const registration = await navigator.serviceWorker.ready;
|
||||
const app = getApps()[0] ?? initializeApp(config);
|
||||
const messaging = getMessaging(app);
|
||||
const token = await getToken(messaging, {
|
||||
vapidKey,
|
||||
serviceWorkerRegistration: registration,
|
||||
});
|
||||
if (!token) {
|
||||
return;
|
||||
}
|
||||
|
||||
const previous = window.localStorage.getItem(WEB_PUSH_TOKEN_KEY);
|
||||
if (previous && previous !== token) {
|
||||
await deletePushToken({ platform: "web", token: previous }).catch(() => undefined);
|
||||
}
|
||||
await upsertPushToken({ platform: "web", token, app_version: "web" });
|
||||
window.localStorage.setItem(WEB_PUSH_TOKEN_KEY, token);
|
||||
|
||||
if (!foregroundListenerAttached) {
|
||||
foregroundListenerAttached = true;
|
||||
onMessage(messaging, (payload) => {
|
||||
void showForegroundNotification(payload);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
export async function unregisterWebPushToken(): Promise<void> {
|
||||
const token = window.localStorage.getItem(WEB_PUSH_TOKEN_KEY);
|
||||
if (!token) {
|
||||
return;
|
||||
}
|
||||
await deletePushToken({ platform: "web", token }).catch(() => undefined);
|
||||
window.localStorage.removeItem(WEB_PUSH_TOKEN_KEY);
|
||||
}
|
||||
|
||||
async function showForegroundNotification(payload: MessagePayload): Promise<void> {
|
||||
const data = payload.data ?? {};
|
||||
const chatId = Number(data.chat_id);
|
||||
const messageId = Number(data.message_id);
|
||||
const title = payload.notification?.title ?? "New message";
|
||||
const body = payload.notification?.body ?? "Open chat";
|
||||
if (Number.isFinite(chatId) && Number.isFinite(messageId)) {
|
||||
await showNotificationViaServiceWorker({
|
||||
chatId,
|
||||
messageId,
|
||||
title,
|
||||
body,
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
function getFirebaseConfig():
|
||||
| {
|
||||
apiKey: string;
|
||||
authDomain?: string;
|
||||
projectId: string;
|
||||
storageBucket?: string;
|
||||
messagingSenderId: string;
|
||||
appId: string;
|
||||
}
|
||||
| null {
|
||||
const apiKey = import.meta.env.VITE_FIREBASE_API_KEY?.trim();
|
||||
const projectId = import.meta.env.VITE_FIREBASE_PROJECT_ID?.trim();
|
||||
const messagingSenderId = import.meta.env.VITE_FIREBASE_MESSAGING_SENDER_ID?.trim();
|
||||
const appId = import.meta.env.VITE_FIREBASE_APP_ID?.trim();
|
||||
if (!apiKey || !projectId || !messagingSenderId || !appId) {
|
||||
return null;
|
||||
}
|
||||
return {
|
||||
apiKey,
|
||||
authDomain: import.meta.env.VITE_FIREBASE_AUTH_DOMAIN?.trim() || undefined,
|
||||
projectId,
|
||||
storageBucket: import.meta.env.VITE_FIREBASE_STORAGE_BUCKET?.trim() || undefined,
|
||||
messagingSenderId,
|
||||
appId,
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user