send notif after chat
This commit is contained in:
@@ -44,7 +44,6 @@ import { TicketModule } from './modules/ticket/ticket.module';
|
|||||||
ProductModule,
|
ProductModule,
|
||||||
RolesModule,
|
RolesModule,
|
||||||
PaymentModule,
|
PaymentModule,
|
||||||
// OrderModule,
|
|
||||||
NotificationsModule,
|
NotificationsModule,
|
||||||
EventEmitterModule.forRoot(),
|
EventEmitterModule.forRoot(),
|
||||||
PrintModule,
|
PrintModule,
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ import { TicketMessageEnum } from "../../../common/enums/message.enum";
|
|||||||
export class CreateChatDto {
|
export class CreateChatDto {
|
||||||
@IsNotEmpty({ message: TicketMessageEnum.MESSAGE_REQUIRED })
|
@IsNotEmpty({ message: TicketMessageEnum.MESSAGE_REQUIRED })
|
||||||
@IsString({ message: TicketMessageEnum.MESSAGE_STRING })
|
@IsString({ message: TicketMessageEnum.MESSAGE_STRING })
|
||||||
@Length(5, 5000, { message: TicketMessageEnum.MESSAGE_LENGTH })
|
@Length(1, 5000, { message: TicketMessageEnum.MESSAGE_LENGTH })
|
||||||
@ApiProperty({ description: "The message content of the ticket" })
|
@ApiProperty({ description: "The message content of the ticket" })
|
||||||
content: string;
|
content: string;
|
||||||
|
|
||||||
|
|||||||
@@ -7,17 +7,20 @@ import { MikroOrmModule } from "@mikro-orm/nestjs";
|
|||||||
import { AdminModule } from "../admin/admin.module";
|
import { AdminModule } from "../admin/admin.module";
|
||||||
import { UserModule } from "../user/user.module";
|
import { UserModule } from "../user/user.module";
|
||||||
import { JwtModule } from "@nestjs/jwt";
|
import { JwtModule } from "@nestjs/jwt";
|
||||||
|
import { Request } from "../request/entities/request.entity";
|
||||||
|
import { Order } from "../order/entities/order.entity";
|
||||||
|
import { NotificationsModule } from "../notification/notifications.module";
|
||||||
|
import { ChatListeners } from "./listeners/chat.listeners";
|
||||||
|
|
||||||
@Module({
|
@Module({
|
||||||
imports: [
|
imports: [
|
||||||
MikroOrmModule.forFeature([Chat]),
|
MikroOrmModule.forFeature([Chat, Request, Order]),
|
||||||
AdminModule,
|
AdminModule,
|
||||||
UserModule,
|
UserModule,
|
||||||
JwtModule.register({})
|
JwtModule.register({}),
|
||||||
|
NotificationsModule,
|
||||||
],
|
],
|
||||||
providers: [ChattService, ChatRepository],
|
providers: [ChattService, ChatRepository, ChatListeners],
|
||||||
controllers: [ChatController],
|
controllers: [ChatController],
|
||||||
exports: [ChattService, ChatRepository],
|
exports: [ChattService, ChatRepository],
|
||||||
})
|
})
|
||||||
|
|||||||
@@ -0,0 +1,6 @@
|
|||||||
|
export class ChatCreatedByAdminEvent {
|
||||||
|
constructor(
|
||||||
|
public readonly refId: string,
|
||||||
|
public readonly chatId: string,
|
||||||
|
) {}
|
||||||
|
}
|
||||||
@@ -0,0 +1,84 @@
|
|||||||
|
import { Injectable, Logger } from '@nestjs/common';
|
||||||
|
import { OnEvent } from '@nestjs/event-emitter';
|
||||||
|
import { EntityManager } from '@mikro-orm/postgresql';
|
||||||
|
import { Request } from 'src/modules/request/entities/request.entity';
|
||||||
|
import { Order } from 'src/modules/order/entities/order.entity';
|
||||||
|
import { NotificationService } from 'src/modules/notification/services/notification.service';
|
||||||
|
import { NotifChannelEnum, NotifTitle } from 'src/modules/notification/interfaces/notification.interface';
|
||||||
|
import { ChatCreatedByAdminEvent } from '../events/chat.events';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class ChatListeners {
|
||||||
|
private readonly logger = new Logger(ChatListeners.name);
|
||||||
|
|
||||||
|
constructor(
|
||||||
|
private readonly em: EntityManager,
|
||||||
|
private readonly notificationService: NotificationService,
|
||||||
|
) {}
|
||||||
|
|
||||||
|
@OnEvent(ChatCreatedByAdminEvent.name)
|
||||||
|
async handleChatCreatedByAdmin(event: ChatCreatedByAdminEvent) {
|
||||||
|
try {
|
||||||
|
this.logger.log(
|
||||||
|
`Chat created by admin: refId=${event.refId}, chatId=${event.chatId}`,
|
||||||
|
);
|
||||||
|
|
||||||
|
const user = await this.findUserByRefId(event.refId);
|
||||||
|
if (!user) {
|
||||||
|
this.logger.warn(
|
||||||
|
`No user found for refId=${event.refId}, skipping notification`,
|
||||||
|
);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const body = 'پیام جدید از پشتیبانی برای شما ارسال شده است.';
|
||||||
|
|
||||||
|
await this.notificationService.sendNotification({
|
||||||
|
channels: [NotifChannelEnum.SMS],
|
||||||
|
recipients: [{ userId: user.id }],
|
||||||
|
message: {
|
||||||
|
title: NotifTitle.NEW_TICKET,
|
||||||
|
content: body,
|
||||||
|
sms: {
|
||||||
|
templateId: '',
|
||||||
|
parameters: {},
|
||||||
|
},
|
||||||
|
},
|
||||||
|
});
|
||||||
|
|
||||||
|
this.logger.log(
|
||||||
|
`Notification sent to user ${user.id} for admin chat on refId=${event.refId}`,
|
||||||
|
);
|
||||||
|
} catch (error) {
|
||||||
|
this.logger.error(
|
||||||
|
`Failed to send notification for chat created by admin: refId=${event.refId}`,
|
||||||
|
error instanceof Error ? error.stack : String(error),
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Find the user associated with refId: first search in requests, then in orders.
|
||||||
|
*/
|
||||||
|
private async findUserByRefId(refId: string): Promise<{ id: string } | null> {
|
||||||
|
const request = await this.em.findOne(
|
||||||
|
Request,
|
||||||
|
{ id: refId },
|
||||||
|
{ populate: ['user'], fields: ['id', 'user'] },
|
||||||
|
);
|
||||||
|
if (request?.user?.id) {
|
||||||
|
return { id: request.user.id };
|
||||||
|
}
|
||||||
|
|
||||||
|
const order = await this.em.findOne(
|
||||||
|
Order,
|
||||||
|
{ id: refId },
|
||||||
|
{ populate: ['user'], fields: ['id', 'user'] },
|
||||||
|
);
|
||||||
|
if (order?.user?.id) {
|
||||||
|
return { id: order.user.id };
|
||||||
|
}
|
||||||
|
|
||||||
|
return null;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -9,6 +9,8 @@ import { UpdateChatDto } from "../DTO/update-chat.dto";
|
|||||||
import { Chat } from "../entities/ticket.entity";
|
import { Chat } from "../entities/ticket.entity";
|
||||||
import { AdminService } from "src/modules/admin/providers/admin.service";
|
import { AdminService } from "src/modules/admin/providers/admin.service";
|
||||||
import { UserService } from "src/modules/user/providers/user.service";
|
import { UserService } from "src/modules/user/providers/user.service";
|
||||||
|
import { EventEmitter2 } from "@nestjs/event-emitter";
|
||||||
|
import { ChatCreatedByAdminEvent } from "../events/chat.events";
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class ChattService {
|
export class ChattService {
|
||||||
@@ -18,18 +20,22 @@ export class ChattService {
|
|||||||
private readonly adminService: AdminService,
|
private readonly adminService: AdminService,
|
||||||
private readonly userService: UserService,
|
private readonly userService: UserService,
|
||||||
private readonly em: EntityManager,
|
private readonly em: EntityManager,
|
||||||
|
private readonly eventEmitter: EventEmitter2,
|
||||||
) { }
|
) { }
|
||||||
|
|
||||||
async createChatAsAdmin(refId: string, dto: CreateChatDto, adminId: string) {
|
async createChatAsAdmin(refId: string, dto: CreateChatDto, adminId: string) {
|
||||||
|
|
||||||
// const orderItem = await this.findOrderItemOrFail(refId)
|
|
||||||
|
|
||||||
let admin: null | Admin = null
|
let admin: null | Admin = null
|
||||||
|
|
||||||
admin = await this.adminService.findOrFail(adminId)
|
admin = await this.adminService.findOrFail(adminId)
|
||||||
|
|
||||||
const ticket = await this.createChat(refId, dto, undefined, admin)
|
const ticket = await this.createChat(refId, dto, undefined, admin)
|
||||||
|
|
||||||
|
this.eventEmitter.emit(
|
||||||
|
ChatCreatedByAdminEvent.name,
|
||||||
|
new ChatCreatedByAdminEvent(refId, ticket.id),
|
||||||
|
);
|
||||||
|
|
||||||
return ticket
|
return ticket
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user