import { Injectable, NotFoundException } from '@nestjs/common'; import { InjectRepository } from '@nestjs/typeorm'; import { Repository } from 'typeorm'; import dayjs from '../../../plugins/dayjs'; import { EncryptionService } from '../../encryption/services/EncryptionService'; import { NotificationService } from '../../notifications/services/NotificationService'; import { Order } from '../entities/Order'; import { OrderMessage } from '../entities/OrderMessage'; import { OrderMessageSender } from '../types/OrderMessageSender'; @Injectable() export class OrderChatService { constructor( @InjectRepository(Order) private readonly orderRepo: Repository, @InjectRepository(OrderMessage) private readonly messageRepo: Repository, private readonly encryptionService: EncryptionService, private readonly notificationService: NotificationService ) {} async listMessagesForOrder(orderId: string): Promise { const messages = await this.messageRepo.find({ where: { order: { id: orderId } }, order: { createdAt: 'ASC' } }); this.encryptionService.decryptPlaintextFieldInPlace(messages, 'body'); return messages; } countUnreadBuyerMessages(order: Pick): number { const readAfter = order.staffChatLastReadAt ? dayjs(order.staffChatLastReadAt) : dayjs(0); return (order.messages ?? []).filter( message => message.sender === OrderMessageSender.Buyer && dayjs(message.createdAt).isAfter(readAfter) ).length; } async markChatRead(orderId: string): Promise { const orderExists = await this.orderRepo.exists({ where: { id: orderId } }); if (!orderExists) { throw new NotFoundException('Order not found'); } await this.orderRepo.update(orderId, { staffChatLastReadAt: new Date() }); } async createMessage(orderId: string, sender: OrderMessageSender, body: string): Promise { const orderExists = await this.orderRepo.exists({ where: { id: orderId } }); if (!orderExists) { throw new NotFoundException('Order not found'); } const entity = this.messageRepo.create({ order: { id: orderId }, sender, body: this.encryptionService.encryptPlaintext(body) }); await this.messageRepo.insert(entity); if (sender === OrderMessageSender.Buyer) { this.notificationService.sendNotification(orderId, 'newBuyerMessage'); } return this.listMessagesForOrder(orderId); } async deleteMessage(orderId: string, messageId: string, sender: OrderMessageSender): Promise { const message = await this.messageRepo.findOne({ where: { id: messageId, order: { id: orderId }, sender } }); if (!message) { throw new NotFoundException('We could not find that message.'); } await this.messageRepo.delete(message.id); return this.listMessagesForOrder(orderId); } }