Files
cat-sitting-planner/lib/notifications.ts

85 lines
3.2 KiB
TypeScript

export async function sendNotification(webhookUrl: string | null, message: string) {
if (!webhookUrl) return;
try {
const response = await fetch(webhookUrl, {
method: "POST",
headers: {
"Content-Type": "application/json",
"User-Agent": "CatSittingPlanner/1.0"
},
// Works for Discord (content) and generic Telegram Webhook bridges (text)
body: JSON.stringify({
content: message,
text: message
}),
});
if (!response.ok) {
console.error(`[Notification] Webhook failed with status ${response.status}`);
}
} catch (error) {
console.error("Failed to send notification:", error);
}
}
import { sendPushNotification } from "./push";
import prisma from "@/lib/prisma";
export async function sendPlanNotification(planId: string, message: string, webhookUrl?: string | null) {
// Parallelize sending
const promises: Promise<any>[] = [];
if (webhookUrl) {
promises.push(sendNotification(webhookUrl, message));
}
try {
const subscriptions = await prisma.pushSubscription.findMany({
where: { planId }
});
if (subscriptions.length > 0) {
console.log(`[Push] Found ${subscriptions.length} subscriptions for plan ${planId}`);
const payload = {
title: "Cat Sitting Planner",
body: message,
url: `/`
// We could pass specific URL if needed, but for now root is okay or dashboard?
// The service worker opens the URL.
// Ideally, we want to open `/dashboard/[planId]`.
};
// Refine URL in payload
// We need 'lang'. We don't have it here easily unless passed.
// But we can guess or just link to root and let redirect handle it?
// Or just link to context.
// Let's rely on SW opening `/`.
subscriptions.forEach(sub => {
promises.push((async () => {
try {
console.log(`[Push] Sending to endpoint ${sub.endpoint.slice(0, 20)}...`);
const res = await sendPushNotification(sub, payload);
console.log(`[Push] Result for ${sub.endpoint.slice(0, 20)}...:`, res);
if (!res.success) {
console.error(`[Push] Failed for endpoint: ${res.statusCode}`);
if (res.statusCode === 410 || res.statusCode === 404) {
console.log(`[Push] Deleting stale subscription`);
await prisma.pushSubscription.delete({ where: { id: sub.id } });
}
}
} catch (err) {
console.error(`[Push] Error inside loop:`, err);
}
})());
});
} else {
console.log(`[Push] No subscriptions found for plan ${planId}`);
}
} catch (e) {
console.error("Failed to fetch/send push subscriptions", e);
}
await Promise.allSettled(promises);
}