This commit is contained in:
2025-12-12 23:14:48 +03:30
parent 0434329db6
commit 6094878e0e
6 changed files with 70 additions and 49 deletions
@@ -53,18 +53,11 @@ interface INotifySms {
phone: string;
subject: NotifTitleEnum;
}
// Sub intefaces
// 1. Order Created Sms Notify Payload
interface IOrderCreatedSmsNotifyPayload extends INotifySmsPayload {
orderNumber: string;
orderAmount: number;
orderDate: Date;
export interface IInAppNotificationPayload {
subject: NotifTitleEnum;
body: string;
}
interface IOrderCreatedSmsNotify extends INotifySms {
subject: NotifTitleEnum.ORDER_CREATED;
payload: IOrderCreatedSmsNotifyPayload;
}
// 2. Payment Success
interface IPaymentSuccessSmsNotifyPayload extends INotifySmsPayload {
amount: number;
@@ -76,4 +69,4 @@ interface IPaymentSuccessSmsNotify extends INotifySms {
payload: IPaymentSuccessSmsNotifyPayload;
}
export type ISmsNotifyPayload = IOrderCreatedSmsNotify | IPaymentSuccessSmsNotify;
export type ISmsNotifyPayload = IPaymentSuccessSmsNotify;
@@ -12,14 +12,15 @@ import { Logger, UseGuards, Inject, forwardRef } from '@nestjs/common';
// import { WsRestId } from './decorators/ws-rest-id.decorator';
import { NotificationService } from './services/notification.service';
import { WsAdminAuthGuard, type AuthenticatedSocket } from './guards/ws-admin-auth.guard';
import { ModuleRef } from '@nestjs/core';
import { ExecutionContext } from '@nestjs/common';
import { IInAppNotificationPayload } from './interfaces/notification.interface';
@UseGuards(WsAdminAuthGuard)
@WebSocketGateway({
cors: {
origin: true,
credentials: true,
},
// connectionGuard: WsAdminAuthGuard,
namespace: '/notifications',
transports: ['websocket', 'polling'],
})
@@ -32,21 +33,31 @@ export class NotificationsGateway implements OnGatewayConnection, OnGatewayDisco
constructor(
@Inject(forwardRef(() => NotificationService))
private readonly notificationService: NotificationService,
private readonly moduleRef: ModuleRef,
) {}
handleConnection(client: AuthenticatedSocket) {
this.logger.log(`Admin connected: ${client.adminId}`);
this.handleJoinRoom(client);
async handleConnection(client: Socket) {
try {
await this.authenticateConnection(client);
const authenticatedClient = client as AuthenticatedSocket;
this.logger.log(`Admin connected: ${authenticatedClient.adminId}`);
this.handleJoinRoom(authenticatedClient);
} catch (error) {
this.logger.error(
`Connection authentication failed: ${error instanceof Error ? error.message : 'Unknown error'}`,
);
client.disconnect();
}
}
handleDisconnect(client: Socket) {
this.logger.log(`Client disconnected: ${client.id}`);
}
sendInAppNotification(repipient: { adminId: string; restaurantId: string }, event: string, data: any) {
sendInAppNotification(repipient: { adminId: string; restaurantId: string }, payload: IInAppNotificationPayload) {
this.logger.log(`Sending in app notification to admin: ${repipient.adminId}`);
const room = this.getRoom(repipient.adminId, repipient.restaurantId);
this.server.to(room).emit(event, data);
this.server.to(room).emit('notifications', payload);
this.logger.log(`In app notification sent to admin: ${repipient.adminId}`);
}
@@ -251,4 +262,18 @@ export class NotificationsGateway implements OnGatewayConnection, OnGatewayDisco
// });
// this.logger.log(`Emitted pager:status:updated to room: ${cookieRoom}`);
// }
private async authenticateConnection(client: Socket): Promise<void> {
const guard = this.moduleRef.get(WsAdminAuthGuard);
const context = {
switchToWs: () => ({ getClient: () => client }),
getClass: () => NotificationsGateway,
getHandler: () => this.handleConnection,
} as unknown as ExecutionContext;
const canActivate = await guard.canActivate(context);
if (!canActivate) {
throw new Error('Authentication failed');
}
}
}
@@ -44,30 +44,30 @@ export class SmsProcessor extends WorkerHost {
// Send SMS notification
let smsResult: ISmsResponse;
if (title === NotifTitleEnum.ORDER_CREATED) {
smsResult = await this.smsAdaptorService.sendNotifySms({
phone: user.phone,
subject: NotifTitleEnum.ORDER_CREATED,
payload: {
orderNumber: '1234567890',
orderAmount: 100000,
orderDate: new Date(),
},
});
} else {
smsResult = await this.smsAdaptorService.sendNotifySms({
phone: user.phone,
subject: NotifTitleEnum.PAYMENT_SUCCESS,
payload: {
amount: 100000,
date: new Date(),
},
});
}
// if (title === NotifTitleEnum.ORDER_CREATED) {
// smsResult = await this.smsAdaptorService.sendNotifySms({
// phone: user.phone,
// subject: NotifTitleEnum.ORDER_CREATED,
// payload: {
// orderNumber: '1234567890',
// orderAmount: 100000,
// orderDate: new Date(),
// },
// });
// } else {
// smsResult = await this.smsAdaptorService.sendNotifySms({
// phone: user.phone,
// subject: NotifTitleEnum.PAYMENT_SUCCESS,
// payload: {
// amount: 100000,
// date: new Date(),
// },
// });
// }
if (smsResult.status !== 1) {
throw new Error(smsResult.message ?? 'Failed to send SMS notification');
}
// if (smsResult.status !== 1) {
// throw new Error(smsResult.message ?? 'Failed to send SMS notification');
// }
// Mark notification as sent
@@ -46,10 +46,13 @@ export class NotificationService {
if (preference?.channels?.includes(NotifChannelEnum.IN_APP)) {
recipients.forEach(recipient => {
if ('adminId' in recipient) {
this.notificationGateway.sendInAppNotification({ adminId: recipient.adminId, restaurantId }, 'notification', {
title: message.subject,
content: message.body,
});
this.notificationGateway.sendInAppNotification(
{ adminId: recipient.adminId, restaurantId },
{
subject: message.subject,
body: message.body,
},
);
}
});
}
@@ -20,9 +20,9 @@ export class SmsAdaptorService {
const { phone, subject, payload } = params;
let templateId!: string;
switch (subject) {
case NotifTitleEnum.ORDER_CREATED:
templateId = this.smsPatternOrderCreated;
break;
// case NotifTitleEnum.ORDER_CREATED:
// templateId = this.smsPatternOrderCreated;
// break;
case NotifTitleEnum.PAYMENT_SUCCESS:
templateId = this.smsPatternPaymentSuccess;
break;
+1 -1
View File
@@ -370,7 +370,7 @@
addEvent('ERROR', `Connection error: ${error.message}`);
});
socket.on('notifications:list', data => {
socket.on('notifications', data => {
addEvent('SUCCESS', `Received ${data.notifications?.length || 0} notifications`, data);
displayNotifications(data.notifications || []);
});