import webpush from "web-push"; import type { ApprovalType } from "@prisma/client"; import { approvalLabel } from "@/lib/domain"; import prisma from "@/lib/prisma"; type PushTargetExpense = { id: string; title: string; amount: number; }; function configureWebPush() { const publicKey = process.env.NEXT_PUBLIC_VAPID_PUBLIC_KEY; const privateKey = process.env.VAPID_PRIVATE_KEY; const subject = process.env.VAPID_SUBJECT; if (!publicKey || !privateKey || !subject) { return false; } webpush.setVapidDetails(subject, publicKey, privateKey); return true; } export function getApprovalRole(approvalType: ApprovalType) { switch (approvalType) { case "CHAIR_A": return "ORGA"; case "CHAIR_B": return "BOARD"; case "FINANCE": return "FINANCE"; } } export async function notifyApprovalRequest(expense: PushTargetExpense, approvalTypes: ApprovalType[]) { if (!configureWebPush() || approvalTypes.length === 0) { return; } const roles = approvalTypes.map(getApprovalRole); const subscriptions = await prisma.pushSubscription.findMany({ where: { user: { role: { in: roles } } }, include: { user: { select: { role: true } } } }); await Promise.all( subscriptions.map(async (subscription) => { const approvalType = approvalTypes.find((type) => getApprovalRole(type) === subscription.user.role); const payload = JSON.stringify({ title: "Freigabe angefragt", body: `${expense.title} (${expense.amount.toFixed(2)} EUR) braucht ${approvalType ? approvalLabel(approvalType) : "deine Freigabe"}.`, url: `/?expense=${encodeURIComponent(expense.id)}`, tag: `approval-${expense.id}-${subscription.user.role}` }); try { await webpush.sendNotification( { endpoint: subscription.endpoint, keys: { p256dh: subscription.p256dh, auth: subscription.auth } }, payload ); } catch (error) { const statusCode = typeof error === "object" && error && "statusCode" in error ? error.statusCode : null; if (statusCode === 404 || statusCode === 410) { await prisma.pushSubscription.delete({ where: { endpoint: subscription.endpoint } }); } } }) ); }