diff --git a/client/public/sw.js b/client/public/sw.js index 46b2e56..a86cec5 100644 --- a/client/public/sw.js +++ b/client/public/sw.js @@ -7,12 +7,30 @@ self.addEventListener('push', (event) => { body: data.body, icon: '/favicon.ico', tag: 'lunch-reminder', + actions: [ + { action: 'neobedvam', title: 'Mám vlastní/neobědvám' }, + ], }) ); }); self.addEventListener('notificationclick', (event) => { event.notification.close(); + + if (event.action === 'neobedvam') { + event.waitUntil( + self.registration.pushManager.getSubscription().then((subscription) => { + if (!subscription) return; + return fetch('/api/notifications/push/quickChoice', { + method: 'POST', + headers: { 'Content-Type': 'application/json' }, + body: JSON.stringify({ endpoint: subscription.endpoint }), + }); + }) + ); + return; + } + event.waitUntil( self.clients.matchAll({ type: 'window' }).then((clientList) => { // Pokud je již otevřené okno, zaostříme na něj diff --git a/server/src/pushReminder.ts b/server/src/pushReminder.ts index d3e499d..02dcc37 100644 --- a/server/src/pushReminder.ts +++ b/server/src/pushReminder.ts @@ -68,6 +68,17 @@ export function getVapidPublicKey(): string | undefined { return process.env.VAPID_PUBLIC_KEY; } +/** Najde login uživatele podle push subscription endpointu. */ +export async function findLoginByEndpoint(endpoint: string): Promise { + const registry = await getRegistry(); + for (const [login, entry] of Object.entries(registry)) { + if (entry.subscription.endpoint === endpoint) { + return login; + } + } + return undefined; +} + /** Zkontroluje a odešle připomínky uživatelům, kteří si nezvolili oběd. */ async function checkAndSendReminders(): Promise { // Přeskočit víkendy diff --git a/server/src/routes/notificationRoutes.ts b/server/src/routes/notificationRoutes.ts index c377829..0ab550a 100644 --- a/server/src/routes/notificationRoutes.ts +++ b/server/src/routes/notificationRoutes.ts @@ -2,7 +2,9 @@ import express, { Request } from "express"; import { getLogin } from "../auth"; import { parseToken } from "../utils"; import { getNotificationSettings, saveNotificationSettings } from "../notifikace"; -import { subscribePush, unsubscribePush, getVapidPublicKey } from "../pushReminder"; +import { subscribePush, unsubscribePush, getVapidPublicKey, findLoginByEndpoint } from "../pushReminder"; +import { addChoice } from "../service"; +import { getWebsocket } from "../websocket"; import { UpdateNotificationSettingsData } from "../../../types"; const router = express.Router(); @@ -64,4 +66,21 @@ router.post("/push/unsubscribe", async (req, res, next) => { } catch (e: any) { next(e) } }); +/** Rychlá akce z push notifikace — nastaví volbu bez JWT (identita přes subscription endpoint). */ +router.post("/push/quickChoice", async (req, res, next) => { + try { + const { endpoint } = req.body; + if (!endpoint) { + return res.status(400).json({ error: "Nebyl předán endpoint" }); + } + const login = await findLoginByEndpoint(endpoint); + if (!login) { + return res.status(404).json({ error: "Subscription nenalezena" }); + } + const data = await addChoice(login, false, 'NEOBEDVAM', undefined, undefined); + getWebsocket().emit("message", data); + res.status(200).json({}); + } catch (e: any) { next(e) } +}); + export default router;