From 4a424b68a2e7472e7e4b8302dd56acd6e0ddf19d Mon Sep 17 00:00:00 2001 From: Kirill Date: Mon, 18 May 2026 11:31:16 +0500 Subject: [PATCH] feat: add notification preferences resolver --- server/src/lib/notifications/preferences.js | 100 ++++++++++++++++++++ 1 file changed, 100 insertions(+) create mode 100644 server/src/lib/notifications/preferences.js diff --git a/server/src/lib/notifications/preferences.js b/server/src/lib/notifications/preferences.js new file mode 100644 index 0000000..7ae2e15 --- /dev/null +++ b/server/src/lib/notifications/preferences.js @@ -0,0 +1,100 @@ +import { prisma } from '../prisma.js' +import { NOTIFICATION_EVENTS } from '../../../shared/constants/notification-events.js' + +const { + ORDER_CREATED, + ORDER_STATUS_CHANGED, + ORDER_MESSAGE_SENT, + ORDER_MESSAGE_ADMIN_REPLY, + PAYMENT_STATUS_CHANGED, + AUTH_CODE_REQUESTED, +} = NOTIFICATION_EVENTS + +const userEventFieldMap = { + [ORDER_CREATED]: 'orderCreated', + [ORDER_STATUS_CHANGED]: 'orderStatusChanged', + [ORDER_MESSAGE_ADMIN_REPLY]: 'orderMessageReceived', + [PAYMENT_STATUS_CHANGED]: 'paymentStatusChanged', +} + +const adminEventFieldMap = { + [ORDER_CREATED]: 'newOrder', + [ORDER_MESSAGE_SENT]: 'newOrderMessage', + 'review:created': 'newReview', +} + +export async function resolveUserNotificationTargets(eventType, payload) { + const targets = [] + + if (payload.userId) { + const prefs = await prisma.notificationPreference.findUnique({ + where: { userId: payload.userId }, + }) + + if (prefs && prefs.globalEnabled) { + const field = userEventFieldMap[eventType] + if (field && prefs[field]) { + const user = await prisma.user.findUnique({ where: { id: payload.userId }, select: { email: true } }) + if (user) { + targets.push({ channel: 'email', recipient: user.email }) + } + } + } + } + + return targets +} + +export async function resolveAdminNotificationTargets(eventType, payload) { + const targets = [] + const settings = await prisma.adminNotificationSettings.findFirst() + if (!settings) return targets + + const field = adminEventFieldMap[eventType] + if (field === 'newReview') { + if (!settings.newReview) return targets + } else if (field && !settings[field]) { + return targets + } + + if (settings.emailEnabled) { + const admin = await prisma.user.findFirst({ + where: { email: process.env.ADMIN_EMAIL }, + select: { email: true }, + }) + if (admin) { + targets.push({ channel: 'email', recipient: admin.email }) + } + } + + if (settings.telegramEnabled && settings.telegramChatId) { + targets.push({ channel: 'telegram', recipient: settings.telegramChatId }) + } + + return targets +} + +export async function resolveAuthCodeTargets(eventType, payload) { + const targets = [] + + if (payload.email) { + targets.push({ channel: 'email', recipient: payload.email }) + } + + if (payload.isAdmin) { + const settings = await prisma.adminNotificationSettings.findFirst() + if (settings && settings.telegramEnabled && settings.telegramChatId && settings.authCodeDuplicate) { + targets.push({ channel: 'telegram', recipient: settings.telegramChatId }) + } + } + + return targets +} + +export async function ensureUserNotificationPreference(userId) { + const existing = await prisma.notificationPreference.findUnique({ where: { userId } }) + if (existing) return existing + return prisma.notificationPreference.create({ + data: { userId, globalEnabled: true }, + }) +}