update
This commit is contained in:
@@ -53,18 +53,11 @@ interface INotifySms {
|
|||||||
phone: string;
|
phone: string;
|
||||||
subject: NotifTitleEnum;
|
subject: NotifTitleEnum;
|
||||||
}
|
}
|
||||||
// Sub intefaces
|
export interface IInAppNotificationPayload {
|
||||||
// 1. Order Created Sms Notify Payload
|
subject: NotifTitleEnum;
|
||||||
interface IOrderCreatedSmsNotifyPayload extends INotifySmsPayload {
|
body: string;
|
||||||
orderNumber: string;
|
|
||||||
orderAmount: number;
|
|
||||||
orderDate: Date;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
interface IOrderCreatedSmsNotify extends INotifySms {
|
|
||||||
subject: NotifTitleEnum.ORDER_CREATED;
|
|
||||||
payload: IOrderCreatedSmsNotifyPayload;
|
|
||||||
}
|
|
||||||
// 2. Payment Success
|
// 2. Payment Success
|
||||||
interface IPaymentSuccessSmsNotifyPayload extends INotifySmsPayload {
|
interface IPaymentSuccessSmsNotifyPayload extends INotifySmsPayload {
|
||||||
amount: number;
|
amount: number;
|
||||||
@@ -76,4 +69,4 @@ interface IPaymentSuccessSmsNotify extends INotifySms {
|
|||||||
payload: IPaymentSuccessSmsNotifyPayload;
|
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 { WsRestId } from './decorators/ws-rest-id.decorator';
|
||||||
import { NotificationService } from './services/notification.service';
|
import { NotificationService } from './services/notification.service';
|
||||||
import { WsAdminAuthGuard, type AuthenticatedSocket } from './guards/ws-admin-auth.guard';
|
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({
|
@WebSocketGateway({
|
||||||
cors: {
|
cors: {
|
||||||
origin: true,
|
origin: true,
|
||||||
credentials: true,
|
credentials: true,
|
||||||
},
|
},
|
||||||
// connectionGuard: WsAdminAuthGuard,
|
|
||||||
namespace: '/notifications',
|
namespace: '/notifications',
|
||||||
transports: ['websocket', 'polling'],
|
transports: ['websocket', 'polling'],
|
||||||
})
|
})
|
||||||
@@ -32,21 +33,31 @@ export class NotificationsGateway implements OnGatewayConnection, OnGatewayDisco
|
|||||||
constructor(
|
constructor(
|
||||||
@Inject(forwardRef(() => NotificationService))
|
@Inject(forwardRef(() => NotificationService))
|
||||||
private readonly notificationService: NotificationService,
|
private readonly notificationService: NotificationService,
|
||||||
|
private readonly moduleRef: ModuleRef,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
handleConnection(client: AuthenticatedSocket) {
|
async handleConnection(client: Socket) {
|
||||||
this.logger.log(`Admin connected: ${client.adminId}`);
|
try {
|
||||||
this.handleJoinRoom(client);
|
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) {
|
handleDisconnect(client: Socket) {
|
||||||
this.logger.log(`Client disconnected: ${client.id}`);
|
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}`);
|
this.logger.log(`Sending in app notification to admin: ${repipient.adminId}`);
|
||||||
const room = this.getRoom(repipient.adminId, repipient.restaurantId);
|
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}`);
|
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}`);
|
// 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
|
// Send SMS notification
|
||||||
let smsResult: ISmsResponse;
|
let smsResult: ISmsResponse;
|
||||||
if (title === NotifTitleEnum.ORDER_CREATED) {
|
// if (title === NotifTitleEnum.ORDER_CREATED) {
|
||||||
smsResult = await this.smsAdaptorService.sendNotifySms({
|
// smsResult = await this.smsAdaptorService.sendNotifySms({
|
||||||
phone: user.phone,
|
// phone: user.phone,
|
||||||
subject: NotifTitleEnum.ORDER_CREATED,
|
// subject: NotifTitleEnum.ORDER_CREATED,
|
||||||
payload: {
|
// payload: {
|
||||||
orderNumber: '1234567890',
|
// orderNumber: '1234567890',
|
||||||
orderAmount: 100000,
|
// orderAmount: 100000,
|
||||||
orderDate: new Date(),
|
// orderDate: new Date(),
|
||||||
},
|
// },
|
||||||
});
|
// });
|
||||||
} else {
|
// } else {
|
||||||
smsResult = await this.smsAdaptorService.sendNotifySms({
|
// smsResult = await this.smsAdaptorService.sendNotifySms({
|
||||||
phone: user.phone,
|
// phone: user.phone,
|
||||||
subject: NotifTitleEnum.PAYMENT_SUCCESS,
|
// subject: NotifTitleEnum.PAYMENT_SUCCESS,
|
||||||
payload: {
|
// payload: {
|
||||||
amount: 100000,
|
// amount: 100000,
|
||||||
date: new Date(),
|
// date: new Date(),
|
||||||
},
|
// },
|
||||||
});
|
// });
|
||||||
}
|
// }
|
||||||
|
|
||||||
if (smsResult.status !== 1) {
|
// if (smsResult.status !== 1) {
|
||||||
throw new Error(smsResult.message ?? 'Failed to send SMS notification');
|
// throw new Error(smsResult.message ?? 'Failed to send SMS notification');
|
||||||
}
|
// }
|
||||||
|
|
||||||
// Mark notification as sent
|
// Mark notification as sent
|
||||||
|
|
||||||
|
|||||||
@@ -46,10 +46,13 @@ export class NotificationService {
|
|||||||
if (preference?.channels?.includes(NotifChannelEnum.IN_APP)) {
|
if (preference?.channels?.includes(NotifChannelEnum.IN_APP)) {
|
||||||
recipients.forEach(recipient => {
|
recipients.forEach(recipient => {
|
||||||
if ('adminId' in recipient) {
|
if ('adminId' in recipient) {
|
||||||
this.notificationGateway.sendInAppNotification({ adminId: recipient.adminId, restaurantId }, 'notification', {
|
this.notificationGateway.sendInAppNotification(
|
||||||
title: message.subject,
|
{ adminId: recipient.adminId, restaurantId },
|
||||||
content: message.body,
|
{
|
||||||
});
|
subject: message.subject,
|
||||||
|
body: message.body,
|
||||||
|
},
|
||||||
|
);
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -20,9 +20,9 @@ export class SmsAdaptorService {
|
|||||||
const { phone, subject, payload } = params;
|
const { phone, subject, payload } = params;
|
||||||
let templateId!: string;
|
let templateId!: string;
|
||||||
switch (subject) {
|
switch (subject) {
|
||||||
case NotifTitleEnum.ORDER_CREATED:
|
// case NotifTitleEnum.ORDER_CREATED:
|
||||||
templateId = this.smsPatternOrderCreated;
|
// templateId = this.smsPatternOrderCreated;
|
||||||
break;
|
// break;
|
||||||
case NotifTitleEnum.PAYMENT_SUCCESS:
|
case NotifTitleEnum.PAYMENT_SUCCESS:
|
||||||
templateId = this.smsPatternPaymentSuccess;
|
templateId = this.smsPatternPaymentSuccess;
|
||||||
break;
|
break;
|
||||||
|
|||||||
@@ -370,7 +370,7 @@
|
|||||||
addEvent('ERROR', `Connection error: ${error.message}`);
|
addEvent('ERROR', `Connection error: ${error.message}`);
|
||||||
});
|
});
|
||||||
|
|
||||||
socket.on('notifications:list', data => {
|
socket.on('notifications', data => {
|
||||||
addEvent('SUCCESS', `Received ${data.notifications?.length || 0} notifications`, data);
|
addEvent('SUCCESS', `Received ${data.notifications?.length || 0} notifications`, data);
|
||||||
displayNotifications(data.notifications || []);
|
displayNotifications(data.notifications || []);
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user