diff --git a/src/notifications/notifications.module.ts b/src/notifications/notifications.module.ts index 917d4b4..e3fdadc 100644 --- a/src/notifications/notifications.module.ts +++ b/src/notifications/notifications.module.ts @@ -2,9 +2,10 @@ import { Module } from '@nestjs/common'; import { ConfigModule } from '@nestjs/config'; import { NotificationsService } from './notifications.service'; import { NotificationsController } from './notifications.controller'; +import { EmailModule } from '../email'; @Module({ - imports: [ConfigModule], + imports: [ConfigModule, EmailModule], controllers: [NotificationsController], providers: [NotificationsService], exports: [NotificationsService], diff --git a/src/notifications/notifications.service.ts b/src/notifications/notifications.service.ts index 17f588d..c058de4 100644 --- a/src/notifications/notifications.service.ts +++ b/src/notifications/notifications.service.ts @@ -6,6 +6,7 @@ import * as admin from 'firebase-admin'; import * as fs from 'fs'; import * as path from 'path'; import { PrismaService } from '../prisma/prisma.service'; +import { EmailService } from '../email/email.service'; interface FcmToken { token: string; @@ -27,6 +28,7 @@ export class NotificationsService implements OnModuleInit { constructor( private readonly prisma: PrismaService, private readonly configService: ConfigService, + private readonly emailService: EmailService, ) {} onModuleInit() { @@ -221,18 +223,19 @@ export class NotificationsService implements OnModuleInit { actionUrl?: string, data?: Record, ) { - // Check user notification preferences for inApp + // Check user notification preferences const user = await this.prisma.user.findUnique({ where: { id: userId }, - select: { notificationPreferences: true, fcmTokens: true }, + select: { notificationPreferences: true, fcmTokens: true, email: true }, }); if (!user) return; const prefs = user.notificationPreferences as Record | null; const inAppEnabled = prefs?.notifications?.[category]?.inApp !== false; + const emailEnabled = prefs?.notifications?.[category]?.email === true; - // Always persist the in-app notification (if enabled) + // Persist in-app notification (if enabled) if (inAppEnabled) { await this.prisma.notification.create({ data: { @@ -246,7 +249,7 @@ export class NotificationsService implements OnModuleInit { }); } - // Send push notification (if Firebase configured and user has tokens) + // Send push notification via FCM (if enabled and user has tokens) if (inAppEnabled) { await this.sendPushNotification(userId, user, { title, @@ -254,6 +257,47 @@ export class NotificationsService implements OnModuleInit { data, }); } + + // Send email notification (if email preference enabled) + if (emailEnabled && user.email) { + await this.sendEmailNotification(user.email, title, description, actionUrl); + } + } + + private async sendEmailNotification( + email: string, + title: string, + body: string, + actionUrl?: string, + ): Promise { + try { + const frontendUrl = this.configService.get('app.frontendUrl') || 'http://localhost:3000'; + const fullUrl = actionUrl ? `${frontendUrl}${actionUrl}` : frontendUrl; + + await this.emailService.sendEmail({ + to: email, + subject: title, + html: ` +
+
+

RE-Quest

+
+
+

${title}

+

${body}

+ ${actionUrl ? `View Details` : ''} +
+
+

You received this email because of your notification settings on RE-Quest.

+ Manage notification preferences +
+
+ `, + text: `${title}\n\n${body}\n\n${actionUrl ? `View details: ${fullUrl}` : ''}`, + }); + } catch (error) { + this.logger.error(`Failed to send email notification to ${email}: ${error.message}`); + } } private async sendPushNotification(