update notif
This commit is contained in:
@@ -9,19 +9,16 @@ export enum NotifTypeEnum {
|
||||
SYSTEM = 'system',
|
||||
}
|
||||
export enum NotifTitleEnum {
|
||||
PAGER_CREATED = 'pager.created',
|
||||
ORDER_CREATED = 'order.created',
|
||||
PAYMENT_SUCCESS = 'payment.success',
|
||||
REVIEW_CREATED = 'review.created',
|
||||
ORDER_STATUS_CHANGED = 'order.status.changed',
|
||||
}
|
||||
export type recipientType =
|
||||
| { phone: string }
|
||||
| { email: string }
|
||||
| { fcmToken: string }
|
||||
| { userId: string; restaurantId: string };
|
||||
export type recipientType = { userId: string; restaurantId: string } | { adminId: string; restaurantId: string };
|
||||
|
||||
export interface NotifRequestMessage {
|
||||
subject: string;
|
||||
subject: NotifTitleEnum;
|
||||
body: string;
|
||||
smsText: string;
|
||||
pushNotif: {
|
||||
@@ -36,11 +33,11 @@ export interface NotifRequestMessage {
|
||||
}
|
||||
|
||||
export interface NotifRequest {
|
||||
requestId: string;
|
||||
timestamp: Date;
|
||||
notifType: NotifTypeEnum;
|
||||
channels: NotifChannelEnum[];
|
||||
recipient: recipientType;
|
||||
// requestId: string;
|
||||
// timestamp: Date;
|
||||
// notifType: NotifTypeEnum;
|
||||
// channels: NotifChannelEnum[];
|
||||
recipients: recipientType[];
|
||||
message: NotifRequestMessage;
|
||||
metadata: {
|
||||
priority: number;
|
||||
|
||||
@@ -15,78 +15,78 @@ export class NotificationListeners {
|
||||
|
||||
constructor(private readonly notificationService: NotificationService) {}
|
||||
|
||||
@OnEvent(OrderCreatedEvent.name)
|
||||
async handleOrderCreated(event: OrderCreatedEvent) {
|
||||
try {
|
||||
this.logger.log(`Order created event received: ${event.orderNumber}`);
|
||||
console.log('Order created event received: ', event);
|
||||
await this.notificationService.sendNotification({
|
||||
restaurantId: event.restaurantId,
|
||||
userId: event.userId,
|
||||
title: NotifTitleEnum.ORDER_CREATED,
|
||||
content: `Your order #${event.orderNumber} has created successfully`,
|
||||
});
|
||||
} catch (error) {
|
||||
this.logger.error(
|
||||
`Failed to send notification for order.created event: ${event.orderNumber}`,
|
||||
error instanceof Error ? error.stack : String(error),
|
||||
);
|
||||
}
|
||||
}
|
||||
@OnEvent(OrderPaymentSuccessEvent.name)
|
||||
async handleOrderPaymentSuccess(event: OrderPaymentSuccessEvent) {
|
||||
try {
|
||||
this.logger.log(`Order payment success event received: ${event.orderNumber}`);
|
||||
// @OnEvent(OrderCreatedEvent.name)
|
||||
// async handleOrderCreated(event: OrderCreatedEvent) {
|
||||
// try {
|
||||
// this.logger.log(`Order created event received: ${event.orderNumber}`);
|
||||
// console.log('Order created event received: ', event);
|
||||
// await this.notificationService.sendNotification({
|
||||
// restaurantId: event.restaurantId,
|
||||
// userId: event.userId,
|
||||
// title: NotifTitleEnum.ORDER_CREATED,
|
||||
// content: `Your order #${event.orderNumber} has created successfully`,
|
||||
// });
|
||||
// } catch (error) {
|
||||
// this.logger.error(
|
||||
// `Failed to send notification for order.created event: ${event.orderNumber}`,
|
||||
// error instanceof Error ? error.stack : String(error),
|
||||
// );
|
||||
// }
|
||||
// }
|
||||
// @OnEvent(OrderPaymentSuccessEvent.name)
|
||||
// async handleOrderPaymentSuccess(event: OrderPaymentSuccessEvent) {
|
||||
// try {
|
||||
// this.logger.log(`Order payment success event received: ${event.orderNumber}`);
|
||||
|
||||
await this.notificationService.sendNotification({
|
||||
restaurantId: event.restaurantId,
|
||||
userId: event.userId,
|
||||
title: NotifTitleEnum.ORDER_CREATED,
|
||||
content: `Your Payement for order #${event.orderNumber} has been successful Paid ${event.totalAmount}`,
|
||||
});
|
||||
} catch (error) {
|
||||
this.logger.error(
|
||||
`Failed to send notification for order.created event: ${event.orderNumber}`,
|
||||
error instanceof Error ? error.stack : String(error),
|
||||
);
|
||||
}
|
||||
}
|
||||
// await this.notificationService.sendNotification({
|
||||
// restaurantId: event.restaurantId,
|
||||
// userId: event.userId,
|
||||
// title: NotifTitleEnum.ORDER_CREATED,
|
||||
// content: `Your Payement for order #${event.orderNumber} has been successful Paid ${event.totalAmount}`,
|
||||
// });
|
||||
// } catch (error) {
|
||||
// this.logger.error(
|
||||
// `Failed to send notification for order.created event: ${event.orderNumber}`,
|
||||
// error instanceof Error ? error.stack : String(error),
|
||||
// );
|
||||
// }
|
||||
// }
|
||||
|
||||
@OnEvent(ReviewCreatedEvent.name)
|
||||
async handleReviewCreated(event: ReviewCreatedEvent) {
|
||||
try {
|
||||
this.logger.log(`Review created event received: ${event.reviewId}`);
|
||||
// @OnEvent(ReviewCreatedEvent.name)
|
||||
// async handleReviewCreated(event: ReviewCreatedEvent) {
|
||||
// try {
|
||||
// this.logger.log(`Review created event received: ${event.reviewId}`);
|
||||
|
||||
await this.notificationService.sendNotification({
|
||||
restaurantId: event.restaurantId,
|
||||
userId: event.userId,
|
||||
title: NotifTitleEnum.REVIEW_CREATED,
|
||||
content: 'Thank you for your review!',
|
||||
});
|
||||
} catch (error) {
|
||||
this.logger.error(
|
||||
`Failed to send notification for review.created event: ${event.reviewId}`,
|
||||
error instanceof Error ? error.stack : String(error),
|
||||
);
|
||||
}
|
||||
}
|
||||
// await this.notificationService.sendNotification({
|
||||
// restaurantId: event.restaurantId,
|
||||
// userId: event.userId,
|
||||
// title: NotifTitleEnum.REVIEW_CREATED,
|
||||
// content: 'Thank you for your review!',
|
||||
// });
|
||||
// } catch (error) {
|
||||
// this.logger.error(
|
||||
// `Failed to send notification for review.created event: ${event.reviewId}`,
|
||||
// error instanceof Error ? error.stack : String(error),
|
||||
// );
|
||||
// }
|
||||
// }
|
||||
|
||||
@OnEvent(OrderStatusChangedEvent.name)
|
||||
async handleOrderStatusChanged(event: OrderStatusChangedEvent) {
|
||||
try {
|
||||
this.logger.log(`Order status changed: ${event.orderId} from ${event.oldStatus} to ${event.newStatus}`);
|
||||
// @OnEvent(OrderStatusChangedEvent.name)
|
||||
// async handleOrderStatusChanged(event: OrderStatusChangedEvent) {
|
||||
// try {
|
||||
// this.logger.log(`Order status changed: ${event.orderId} from ${event.oldStatus} to ${event.newStatus}`);
|
||||
|
||||
await this.notificationService.sendNotification({
|
||||
restaurantId: event.restaurantId,
|
||||
userId: event.userId,
|
||||
title: NotifTitleEnum.ORDER_STATUS_CHANGED,
|
||||
content: `Your order #${event.orderId} is now ${event.newStatus}`,
|
||||
});
|
||||
} catch (error) {
|
||||
this.logger.error(
|
||||
`Failed to send notification for order.status.changed event: ${event.orderId}`,
|
||||
error instanceof Error ? error.stack : String(error),
|
||||
);
|
||||
}
|
||||
}
|
||||
// await this.notificationService.sendNotification({
|
||||
// restaurantId: event.restaurantId,
|
||||
// userId: event.userId,
|
||||
// title: NotifTitleEnum.ORDER_STATUS_CHANGED,
|
||||
// content: `Your order #${event.orderId} is now ${event.newStatus}`,
|
||||
// });
|
||||
// } catch (error) {
|
||||
// this.logger.error(
|
||||
// `Failed to send notification for order.status.changed event: ${event.orderId}`,
|
||||
// error instanceof Error ? error.stack : String(error),
|
||||
// );
|
||||
// }
|
||||
// }
|
||||
}
|
||||
|
||||
@@ -6,7 +6,7 @@ import { NotificationQueueService } from './notification-queue.service';
|
||||
import { NotificationQueueJob } from '../interfaces/notification-queue.interface';
|
||||
import { Restaurant } from '../../restaurants/entities/restaurant.entity';
|
||||
import { User } from '../../users/entities/user.entity';
|
||||
import { NotifTitleEnum } from '../interfaces/notification.interface';
|
||||
import { NotifChannelEnum, NotifRequest, NotifTitleEnum } from '../interfaces/notification.interface';
|
||||
|
||||
export interface SendNotificationParams {
|
||||
restaurantId: string;
|
||||
@@ -26,52 +26,46 @@ export class NotificationService {
|
||||
private readonly queueService: NotificationQueueService,
|
||||
) {}
|
||||
|
||||
async sendNotification(params: SendNotificationParams): Promise<Notification> {
|
||||
const { restaurantId, userId, title, content } = params;
|
||||
async sendNotification(params: NotifRequest): Promise<Notification[]> {
|
||||
const { recipients, message, metadata } = params;
|
||||
|
||||
// Verify restaurant exists
|
||||
const restaurant = await this.em.findOne(Restaurant, { id: restaurantId });
|
||||
if (!restaurant) {
|
||||
throw new NotFoundException('Restaurant not found');
|
||||
// create Database notifications
|
||||
const notifications = await this.createAdminBulkNotifications(
|
||||
recipients.map(recipient => ({
|
||||
restaurantId: recipient.restaurantId,
|
||||
title: message.subject,
|
||||
content: message.body,
|
||||
adminId: 'adminId' in recipient ? recipient.adminId : null,
|
||||
userId: 'userId' in recipient ? recipient.userId : null,
|
||||
})),
|
||||
);
|
||||
const restaurantId = recipients[0].restaurantId;
|
||||
// get admin prefrences
|
||||
const preference = await this.preferenceService.findByRestaurantAndType(restaurantId, message.subject);
|
||||
|
||||
if (preference?.channels?.length === 0) {
|
||||
this.logger.warn(`Notification type is NONE for restaurant ${restaurantId}, title ${message.subject}`);
|
||||
return notifications;
|
||||
}
|
||||
|
||||
// Get notification preferences
|
||||
const preference = await this.preferenceService.findByRestaurantAndType(restaurantId, title);
|
||||
// const job: NotificationQueueJob = {
|
||||
// restaurantId,
|
||||
// userId,
|
||||
// title,
|
||||
// content,
|
||||
// // idempotencyKey: finalIdempotencyKey,
|
||||
// notificationId: notification.id,
|
||||
// channels: preference.channels,
|
||||
// };
|
||||
|
||||
if (!preference) {
|
||||
this.logger.warn(`Notification preference not found or disabled for restaurant ${restaurantId}, type ${title}`);
|
||||
throw new NotFoundException(`Notification preference not found or disabled for type ${title}`);
|
||||
}
|
||||
|
||||
// Generate idempotency key if not provided
|
||||
// const finalIdempotencyKey = idempotencyKey || `${restaurantId}-${title}-${Date.now()}`;
|
||||
|
||||
// Create notification record
|
||||
const user = userId ? await this.em.findOne(User, { id: userId }) : undefined;
|
||||
const notification = this.em.create(Notification, {
|
||||
restaurant,
|
||||
user,
|
||||
title,
|
||||
content,
|
||||
// idempotencyKey: finalIdempotencyKey,
|
||||
});
|
||||
|
||||
await this.em.persistAndFlush(notification);
|
||||
|
||||
if (preference.channels.length === 0) {
|
||||
this.logger.warn(`Notification type is NONE for restaurant ${restaurantId}, title ${title}`);
|
||||
return notification;
|
||||
}
|
||||
// preference.channels.forEach(channel => {
|
||||
// if (channel === NotifChannelEnum.SMS) {
|
||||
// await this.queueService.addSmsNotification(job);
|
||||
// } else if (channel === NotifChannelEnum.PUSH) {
|
||||
// await this.queueService.addPushNotification(job);
|
||||
// }
|
||||
// });
|
||||
// Add to queue
|
||||
const job: NotificationQueueJob = {
|
||||
restaurantId,
|
||||
userId,
|
||||
title,
|
||||
content,
|
||||
// idempotencyKey: finalIdempotencyKey,
|
||||
notificationId: notification.id,
|
||||
channels: preference.channels,
|
||||
};
|
||||
// if (preference.notificationType === NotificationType.SMS) {
|
||||
// await this.queueService.addSmsNotification(job);
|
||||
// } else if (preference.notificationType === NotificationType.PUSH) {
|
||||
@@ -81,9 +75,30 @@ export class NotificationService {
|
||||
// await this.queueService.addPushNotification(job);
|
||||
// }
|
||||
|
||||
this.logger.log(`Queued notification for restaurant ${restaurantId}, title ${title}`);
|
||||
this.logger.log(`Queued notification for restaurant ${restaurantId}, title ${message.subject}`);
|
||||
|
||||
return notification;
|
||||
return notifications;
|
||||
}
|
||||
|
||||
async createAdminBulkNotifications(
|
||||
params: {
|
||||
restaurantId: string;
|
||||
title: NotifTitleEnum;
|
||||
content: string;
|
||||
adminId: string | null;
|
||||
userId: string | null;
|
||||
}[],
|
||||
): Promise<Notification[]> {
|
||||
const notifications = params.map(param => {
|
||||
return this.em.create(Notification, {
|
||||
restaurant: param.restaurantId,
|
||||
admin: param.adminId,
|
||||
title: param.title,
|
||||
content: param.content,
|
||||
});
|
||||
});
|
||||
await this.em.persistAndFlush(notifications);
|
||||
return notifications;
|
||||
}
|
||||
|
||||
async findOne(id: string): Promise<Notification> {
|
||||
|
||||
Reference in New Issue
Block a user