refactor: update notification titles and enhance notification creation process

- Simplified notification titles by removing emojis for better clarity.
- Modified createNotification method to include automatic publishing to Redis, improving notification delivery.
- Updated email and OTP notification methods to leverage the new createNotification functionality.
This commit is contained in:
Abdalhamid Alhamad
2026-01-06 16:22:21 +03:00
parent 170aa903c7
commit 2c8de913f8
2 changed files with 27 additions and 19 deletions

View File

@ -95,7 +95,7 @@ export class TransactionNotificationListener {
: NotificationScope.CHILD_SPENDING; : NotificationScope.CHILD_SPENDING;
// Construct title // Construct title
const title = isTopUp ? '💰 Card Topped Up' : '💳 Purchase Successful'; const title = isTopUp ? 'Card Topped Up' : 'Purchase Successful';
// Extract data // Extract data
const amount = transaction.transactionAmount; const amount = transaction.transactionAmount;
@ -169,7 +169,7 @@ export class TransactionNotificationListener {
// Send notification to parent // Send notification to parent
await this.notificationFactory.send({ await this.notificationFactory.send({
userId: parentUser.id, userId: parentUser.id,
title: '🚨 Child Spending Alert', title: 'Child Spending Alert',
message: `${childName} spent $${amount.toFixed(2)} at ${merchant}`, message: `${childName} spent $${amount.toFixed(2)} at ${merchant}`,
scope: NotificationScope.PARENT_SPENDING_ALERT, scope: NotificationScope.PARENT_SPENDING_ALERT,
preferences: this.getUserPreferences(parentUser), preferences: this.getUserPreferences(parentUser),
@ -226,7 +226,7 @@ export class TransactionNotificationListener {
// Send notification to parent // Send notification to parent
await this.notificationFactory.send({ await this.notificationFactory.send({
userId: parentUser.id, 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)}`, message: `You topped up ${childName}'s card with $${amount.toFixed(2)}. New balance: $${balance.toFixed(2)}`,
scope: NotificationScope.PARENT_TOP_UP_CONFIRMATION, scope: NotificationScope.PARENT_TOP_UP_CONFIRMATION,
preferences: this.getUserPreferences(parentUser), preferences: this.getUserPreferences(parentUser),

View File

@ -31,9 +31,24 @@ export class NotificationsService {
return { notifications, count, unreadCount }; return { notifications, count, unreadCount };
} }
createNotification(notification: Partial<Notification>) { async createNotification(notification: Partial<Notification>) {
this.logger.log(`Creating notification for user ${notification.userId}`); 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) { markAsRead(userId: string) {
@ -42,35 +57,28 @@ export class NotificationsService {
} }
async sendEmailAsync(data: SendEmailRequestDto) { async sendEmailAsync(data: SendEmailRequestDto) {
this.logger.log(`emitting ${EventType.NOTIFICATION_CREATED} event`); this.logger.log(`Creating email notification for ${data.to}`);
const notification = await this.createNotification({ // createNotification now automatically publishes to Redis
await this.createNotification({
recipient: data.to, recipient: data.to,
title: data.subject, title: data.subject,
message: '', message: '',
scope: NotificationScope.USER_INVITED, scope: NotificationScope.USER_INVITED,
channel: NotificationChannel.EMAIL, channel: NotificationChannel.EMAIL,
}); data: data.data, // Pass data in notification object
// return this.redisPubSubService.emit(EventType.NOTIFICATION_CREATED, notification, data.data);
this.redisPubSubService.publishEvent(EventType.NOTIFICATION_CREATED, {
...notification,
data,
}); });
} }
async sendOtpNotification(sendOtpRequest: ISendOtp, otp: string) { async sendOtpNotification(sendOtpRequest: ISendOtp, otp: string) {
this.logger.log(`Sending OTP to ${sendOtpRequest.recipient}`); 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, recipient: sendOtpRequest.recipient,
title: OTP_TITLE, title: OTP_TITLE,
message: OTP_BODY.replace('{otp}', otp), message: OTP_BODY.replace('{otp}', otp),
scope: NotificationScope.OTP, scope: NotificationScope.OTP,
channel: sendOtpRequest.otpType === OtpType.EMAIL ? NotificationChannel.EMAIL : NotificationChannel.SMS, channel: sendOtpRequest.otpType === OtpType.EMAIL ? NotificationChannel.EMAIL : NotificationChannel.SMS,
}); data: { otp }, // Pass data in notification object
this.logger.log(`emitting ${EventType.NOTIFICATION_CREATED} event`);
return this.redisPubSubService.publishEvent(EventType.NOTIFICATION_CREATED, {
...notification,
data: { otp },
}); });
} }
} }