All checks were successful
ci/woodpecker/push/workflow Pipeline was successful
109 lines
3.7 KiB
TypeScript
109 lines
3.7 KiB
TypeScript
import { getToken } from '../Utils';
|
|
|
|
/** Převede base64url VAPID klíč na Uint8Array pro PushManager. */
|
|
function urlBase64ToUint8Array(base64String: string): Uint8Array {
|
|
const padding = '='.repeat((4 - (base64String.length % 4)) % 4);
|
|
const base64 = (base64String + padding).replace(/-/g, '+').replace(/_/g, '/');
|
|
const rawData = atob(base64);
|
|
const outputArray = new Uint8Array(rawData.length);
|
|
for (let i = 0; i < rawData.length; ++i) {
|
|
outputArray[i] = rawData.charCodeAt(i);
|
|
}
|
|
return outputArray;
|
|
}
|
|
|
|
/** Helper pro autorizované API volání na push endpointy. */
|
|
async function pushApiFetch(path: string, options: RequestInit = {}): Promise<Response> {
|
|
const token = getToken();
|
|
return fetch(`/api/notifications/push${path}`, {
|
|
...options,
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
...(token ? { Authorization: `Bearer ${token}` } : {}),
|
|
...options.headers,
|
|
},
|
|
});
|
|
}
|
|
|
|
/**
|
|
* Zaregistruje service worker, přihlásí se k push notifikacím
|
|
* a odešle subscription na server.
|
|
*/
|
|
export async function subscribeToPush(reminderTime: string): Promise<boolean> {
|
|
if (!('serviceWorker' in navigator) || !('PushManager' in window)) {
|
|
console.warn('Push notifikace nejsou v tomto prohlížeči podporovány');
|
|
return false;
|
|
}
|
|
|
|
try {
|
|
// Registrace service workeru
|
|
const registration = await navigator.serviceWorker.register('/sw.js');
|
|
await navigator.serviceWorker.ready;
|
|
|
|
// Vyžádání oprávnění
|
|
const permission = await Notification.requestPermission();
|
|
if (permission !== 'granted') {
|
|
console.warn('Push notifikace: oprávnění zamítnuto');
|
|
return false;
|
|
}
|
|
|
|
// Získání VAPID veřejného klíče ze serveru
|
|
const vapidResponse = await pushApiFetch('/vapidKey');
|
|
if (!vapidResponse.ok) {
|
|
console.error('Push notifikace: nepodařilo se získat VAPID klíč');
|
|
return false;
|
|
}
|
|
const { key: vapidPublicKey } = await vapidResponse.json();
|
|
|
|
// Přihlášení k push
|
|
const subscription = await registration.pushManager.subscribe({
|
|
userVisibleOnly: true,
|
|
applicationServerKey: urlBase64ToUint8Array(vapidPublicKey) as BufferSource,
|
|
});
|
|
|
|
// Odeslání subscription na server
|
|
const response = await pushApiFetch('/subscribe', {
|
|
method: 'POST',
|
|
body: JSON.stringify({
|
|
subscription: subscription.toJSON(),
|
|
reminderTime,
|
|
}),
|
|
});
|
|
|
|
if (!response.ok) {
|
|
console.error('Push notifikace: nepodařilo se odeslat subscription na server');
|
|
return false;
|
|
}
|
|
|
|
console.log('Push notifikace: úspěšně přihlášeno k připomínkám v', reminderTime);
|
|
return true;
|
|
} catch (error) {
|
|
console.error('Push notifikace: chyba při registraci', error);
|
|
return false;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Odhlásí se z push notifikací a informuje server.
|
|
*/
|
|
export async function unsubscribeFromPush(): Promise<void> {
|
|
if (!('serviceWorker' in navigator)) {
|
|
return;
|
|
}
|
|
|
|
try {
|
|
const registration = await navigator.serviceWorker.getRegistration('/sw.js');
|
|
if (registration) {
|
|
const subscription = await registration.pushManager.getSubscription();
|
|
if (subscription) {
|
|
await subscription.unsubscribe();
|
|
}
|
|
}
|
|
|
|
await pushApiFetch('/unsubscribe', { method: 'POST' });
|
|
console.log('Push notifikace: úspěšně odhlášeno z připomínek');
|
|
} catch (error) {
|
|
console.error('Push notifikace: chyba při odhlášení', error);
|
|
}
|
|
}
|