feat: add email notification functionality to the notifications service by integrating EmailModule and EmailService.
This commit is contained in:
@@ -2,9 +2,10 @@ import { Module } from '@nestjs/common';
|
|||||||
import { ConfigModule } from '@nestjs/config';
|
import { ConfigModule } from '@nestjs/config';
|
||||||
import { NotificationsService } from './notifications.service';
|
import { NotificationsService } from './notifications.service';
|
||||||
import { NotificationsController } from './notifications.controller';
|
import { NotificationsController } from './notifications.controller';
|
||||||
|
import { EmailModule } from '../email';
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
imports: [ConfigModule],
|
imports: [ConfigModule, EmailModule],
|
||||||
controllers: [NotificationsController],
|
controllers: [NotificationsController],
|
||||||
providers: [NotificationsService],
|
providers: [NotificationsService],
|
||||||
exports: [NotificationsService],
|
exports: [NotificationsService],
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import * as admin from 'firebase-admin';
|
|||||||
import * as fs from 'fs';
|
import * as fs from 'fs';
|
||||||
import * as path from 'path';
|
import * as path from 'path';
|
||||||
import { PrismaService } from '../prisma/prisma.service';
|
import { PrismaService } from '../prisma/prisma.service';
|
||||||
|
import { EmailService } from '../email/email.service';
|
||||||
|
|
||||||
interface FcmToken {
|
interface FcmToken {
|
||||||
token: string;
|
token: string;
|
||||||
@@ -27,6 +28,7 @@ export class NotificationsService implements OnModuleInit {
|
|||||||
constructor(
|
constructor(
|
||||||
private readonly prisma: PrismaService,
|
private readonly prisma: PrismaService,
|
||||||
private readonly configService: ConfigService,
|
private readonly configService: ConfigService,
|
||||||
|
private readonly emailService: EmailService,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
onModuleInit() {
|
onModuleInit() {
|
||||||
@@ -221,18 +223,19 @@ export class NotificationsService implements OnModuleInit {
|
|||||||
actionUrl?: string,
|
actionUrl?: string,
|
||||||
data?: Record<string, string>,
|
data?: Record<string, string>,
|
||||||
) {
|
) {
|
||||||
// Check user notification preferences for inApp
|
// Check user notification preferences
|
||||||
const user = await this.prisma.user.findUnique({
|
const user = await this.prisma.user.findUnique({
|
||||||
where: { id: userId },
|
where: { id: userId },
|
||||||
select: { notificationPreferences: true, fcmTokens: true },
|
select: { notificationPreferences: true, fcmTokens: true, email: true },
|
||||||
});
|
});
|
||||||
|
|
||||||
if (!user) return;
|
if (!user) return;
|
||||||
|
|
||||||
const prefs = user.notificationPreferences as Record<string, any> | null;
|
const prefs = user.notificationPreferences as Record<string, any> | null;
|
||||||
const inAppEnabled = prefs?.notifications?.[category]?.inApp !== false;
|
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) {
|
if (inAppEnabled) {
|
||||||
await this.prisma.notification.create({
|
await this.prisma.notification.create({
|
||||||
data: {
|
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) {
|
if (inAppEnabled) {
|
||||||
await this.sendPushNotification(userId, user, {
|
await this.sendPushNotification(userId, user, {
|
||||||
title,
|
title,
|
||||||
@@ -254,6 +257,47 @@ export class NotificationsService implements OnModuleInit {
|
|||||||
data,
|
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<void> {
|
||||||
|
try {
|
||||||
|
const frontendUrl = this.configService.get<string>('app.frontendUrl') || 'http://localhost:3000';
|
||||||
|
const fullUrl = actionUrl ? `${frontendUrl}${actionUrl}` : frontendUrl;
|
||||||
|
|
||||||
|
await this.emailService.sendEmail({
|
||||||
|
to: email,
|
||||||
|
subject: title,
|
||||||
|
html: `
|
||||||
|
<div style="font-family: Arial, sans-serif; max-width: 600px; margin: 0 auto;">
|
||||||
|
<div style="background-color: #00293d; padding: 20px; text-align: center;">
|
||||||
|
<h1 style="color: white; margin: 0; font-size: 20px;">RE-Quest</h1>
|
||||||
|
</div>
|
||||||
|
<div style="padding: 30px 20px;">
|
||||||
|
<h2 style="color: #00293d; font-size: 18px; margin-top: 0;">${title}</h2>
|
||||||
|
<p style="color: #333; font-size: 14px; line-height: 1.6;">${body}</p>
|
||||||
|
${actionUrl ? `<a href="${fullUrl}" style="display: inline-block; background-color: #e58625; color: white; padding: 12px 24px; text-decoration: none; border-radius: 15px; font-weight: bold; margin-top: 15px;">View Details</a>` : ''}
|
||||||
|
</div>
|
||||||
|
<div style="background-color: #f5f5f5; padding: 15px 20px; text-align: center; font-size: 12px; color: #666;">
|
||||||
|
<p>You received this email because of your notification settings on RE-Quest.</p>
|
||||||
|
<a href="${frontendUrl}/agent/settings/notifications" style="color: #e58625;">Manage notification preferences</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
`,
|
||||||
|
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(
|
private async sendPushNotification(
|
||||||
|
|||||||
Reference in New Issue
Block a user