diff --git a/src/common/modules/notification/listeners/transaction-notification.listener.ts b/src/common/modules/notification/listeners/transaction-notification.listener.ts index 758532f..b2612af 100644 --- a/src/common/modules/notification/listeners/transaction-notification.listener.ts +++ b/src/common/modules/notification/listeners/transaction-notification.listener.ts @@ -95,7 +95,7 @@ export class TransactionNotificationListener { : NotificationScope.CHILD_SPENDING; // Construct title - const title = isTopUp ? '💰 Card Topped Up' : '💳 Purchase Successful'; + const title = isTopUp ? 'Card Topped Up' : 'Purchase Successful'; // Extract data const amount = transaction.transactionAmount; @@ -169,7 +169,7 @@ export class TransactionNotificationListener { // Send notification to parent await this.notificationFactory.send({ userId: parentUser.id, - title: '🚨 Child Spending Alert', + title: 'Child Spending Alert', message: `${childName} spent $${amount.toFixed(2)} at ${merchant}`, scope: NotificationScope.PARENT_SPENDING_ALERT, preferences: this.getUserPreferences(parentUser), @@ -226,7 +226,7 @@ export class TransactionNotificationListener { // Send notification to parent await this.notificationFactory.send({ userId: parentUser.id, - title: '✅ Top-Up Confirmation', + title: 'Top-Up Confirmation', message: `You topped up ${childName}'s card with $${amount.toFixed(2)}. New balance: $${balance.toFixed(2)}`, scope: NotificationScope.PARENT_TOP_UP_CONFIRMATION, preferences: this.getUserPreferences(parentUser), diff --git a/src/common/modules/notification/services/notifications.service.ts b/src/common/modules/notification/services/notifications.service.ts index ba192bc..46db986 100644 --- a/src/common/modules/notification/services/notifications.service.ts +++ b/src/common/modules/notification/services/notifications.service.ts @@ -31,9 +31,24 @@ export class NotificationsService { return { notifications, count, unreadCount }; } - createNotification(notification: Partial) { + async createNotification(notification: Partial) { this.logger.log(`Creating notification for user ${notification.userId}`); - return this.notificationRepository.createNotification(notification); + const savedNotification = await this.notificationRepository.createNotification(notification); + + // Publish to Redis PubSub for delivery (Firebase, Email, SMS) + this.logger.log(`Publishing ${EventType.NOTIFICATION_CREATED} event to Redis`); + this.redisPubSubService.publishEvent(EventType.NOTIFICATION_CREATED, { + ...savedNotification, + data: notification.data || savedNotification.data, + }).catch((error) => { + // Log error but don't throw - notification is saved in DB + this.logger.error( + `Failed to publish notification ${savedNotification.id} to Redis: ${error?.message || 'Unknown error'}`, + error?.stack + ); + }); + + return savedNotification; } markAsRead(userId: string) { @@ -42,35 +57,28 @@ export class NotificationsService { } async sendEmailAsync(data: SendEmailRequestDto) { - this.logger.log(`emitting ${EventType.NOTIFICATION_CREATED} event`); - const notification = await this.createNotification({ + this.logger.log(`Creating email notification for ${data.to}`); + // createNotification now automatically publishes to Redis + await this.createNotification({ recipient: data.to, title: data.subject, message: '', scope: NotificationScope.USER_INVITED, channel: NotificationChannel.EMAIL, - }); - // return this.redisPubSubService.emit(EventType.NOTIFICATION_CREATED, notification, data.data); - this.redisPubSubService.publishEvent(EventType.NOTIFICATION_CREATED, { - ...notification, - data, + data: data.data, // Pass data in notification object }); } async sendOtpNotification(sendOtpRequest: ISendOtp, otp: string) { this.logger.log(`Sending OTP to ${sendOtpRequest.recipient}`); - const notification = await this.createNotification({ + // createNotification now automatically publishes to Redis + return 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, - }); - - this.logger.log(`emitting ${EventType.NOTIFICATION_CREATED} event`); - return this.redisPubSubService.publishEvent(EventType.NOTIFICATION_CREATED, { - ...notification, - data: { otp }, + data: { otp }, // Pass data in notification object }); } }