import { Injectable } from '@nestjs/common'; import { EventEmitter2, OnEvent } from '@nestjs/event-emitter'; import { PageOptionsRequestDto } from '~/core/dtos'; import { DeviceService } from '~/user/services'; import { OTP_BODY, OTP_TITLE } from '../../otp/constants'; import { OtpType } from '../../otp/enums'; import { ISendOtp } from '../../otp/interfaces'; import { Notification } from '../entities'; import { EventType, NotificationChannel, NotificationScope } from '../enums'; import { NotificationsRepository } from '../repositories'; import { FirebaseService } from './firebase.service'; import { TwilioService } from './twilio.service'; @Injectable() export class NotificationsService { constructor( private readonly firebaseService: FirebaseService, private readonly notificationRepository: NotificationsRepository, private readonly twilioService: TwilioService, private readonly eventEmitter: EventEmitter2, private readonly deviceService: DeviceService, ) {} async sendPushNotification(userId: string, title: string, body: string) { // Get the device tokens for the user const tokens = await this.deviceService.getTokens(userId); if (!tokens.length) { return; } // Send the notification return this.firebaseService.sendNotification(tokens, title, body); } async sendSMS(to: string, body: string) { await this.twilioService.sendSMS(to, body); } async getNotifications(userId: string, pageOptionsDto: PageOptionsRequestDto) { const [[notifications, count], unreadCount] = await Promise.all([ this.notificationRepository.getNotifications(userId, pageOptionsDto), this.notificationRepository.getUnreadNotificationsCount(userId), ]); return { notifications, count, unreadCount }; } createNotification(notification: Partial) { return this.notificationRepository.createNotification(notification); } markAsRead(userId: string) { return this.notificationRepository.markAsRead(userId); } async sendOtpNotification(sendOtpRequest: ISendOtp, otp: string) { const notification = await this.createNotification({ recipient: sendOtpRequest.recipient, title: OTP_TITLE, message: OTP_BODY.replace('{otp}', otp), scope: NotificationScope.OTP, channel: sendOtpRequest.otpType === OtpType.EMAIL ? NotificationChannel.EMAIL : NotificationChannel.SMS, }); return this.eventEmitter.emit(EventType.NOTIFICATION_CREATED, notification); } @OnEvent(EventType.NOTIFICATION_CREATED) handleNotificationCreatedEvent(notification: Notification) { switch (notification.channel) { case NotificationChannel.SMS: return this.sendSMS(notification.recipient!, notification.message); case NotificationChannel.PUSH: return this.sendPushNotification(notification.userId, notification.title, notification.message); } } }