Files
backend/src/support-chat/support-chat.controller.ts

181 lines
6.1 KiB
TypeScript
Raw Normal View History

import {
Controller,
Get,
Post,
Patch,
Body,
Param,
Query,
UseGuards,
HttpCode,
HttpStatus,
Inject,
forwardRef,
} from '@nestjs/common';
import {
ApiTags,
ApiOperation,
ApiResponse,
ApiBearerAuth,
ApiQuery,
ApiParam,
} from '@nestjs/swagger';
import { SupportChatService } from './support-chat.service';
import { SendSupportMessageDto } from './dto';
import { JwtAuthGuard } from '../auth/guards';
import { CurrentUser } from '../auth/decorators';
import { Roles } from '../auth/decorators/roles.decorator';
import { UserRole, SupportChatStatus } from '@prisma/client';
import { MessagesGateway } from '../messages/messages.gateway';
@ApiTags('Support Chat')
@Controller('support-chat')
@UseGuards(JwtAuthGuard)
@ApiBearerAuth('JWT-auth')
export class SupportChatController {
constructor(
private readonly supportChatService: SupportChatService,
@Inject(forwardRef(() => MessagesGateway))
private readonly messagesGateway: MessagesGateway,
) {}
// ==========================================
// GET OR CREATE SUPPORT CHAT (User/Agent)
// ==========================================
@Post()
@HttpCode(HttpStatus.OK)
@ApiOperation({ summary: 'Get or create a support chat for the current user' })
async getOrCreateChat(@CurrentUser('id') userId: string) {
return this.supportChatService.getOrCreateChat(userId);
}
// ==========================================
// GET MY SUPPORT CHAT (User/Agent)
// ==========================================
@Get('my')
@ApiOperation({ summary: 'Get current user\'s open support chat' })
async getMyChat(@CurrentUser('id') userId: string) {
return this.supportChatService.getOrCreateChat(userId);
}
// ==========================================
// GET MESSAGES
// ==========================================
@Get(':id/messages')
@ApiOperation({ summary: 'Get messages for a support chat' })
@ApiParam({ name: 'id', description: 'Support Chat ID' })
@ApiQuery({ name: 'page', required: false, type: Number })
@ApiQuery({ name: 'limit', required: false, type: Number })
async getMessages(
@Param('id') chatId: string,
@CurrentUser('id') userId: string,
@CurrentUser('role') role: UserRole,
@Query('page') page?: string,
@Query('limit') limit?: string,
) {
// Validate access
const isAdmin = role === UserRole.ADMIN;
await this.supportChatService.getChat(chatId, userId, isAdmin);
return this.supportChatService.getMessages(
chatId,
page ? parseInt(page, 10) : 1,
limit ? parseInt(limit, 10) : 50,
);
}
// ==========================================
// SEND MESSAGE (REST fallback)
// ==========================================
@Post(':id/messages')
@HttpCode(HttpStatus.CREATED)
@ApiOperation({ summary: 'Send a message in a support chat' })
@ApiParam({ name: 'id', description: 'Support Chat ID' })
async sendMessage(
@Param('id') chatId: string,
@CurrentUser('id') userId: string,
@CurrentUser('role') role: UserRole,
@Body() dto: SendSupportMessageDto,
) {
// Validate access
const isAdmin = role === UserRole.ADMIN;
await this.supportChatService.getChat(chatId, userId, isAdmin);
const senderRole = role === UserRole.ADMIN ? 'ADMIN' : 'USER';
const message = await this.supportChatService.sendMessage(chatId, userId, senderRole, dto.content);
// Emit WebSocket events for real-time updates
this.messagesGateway.server.to(`support:${chatId}`).emit('support_new_message', message);
// If user/agent sent the message, notify admins about unread count
if (senderRole !== 'ADMIN') {
const unreadTotal = await this.supportChatService.getAdminUnreadTotal();
this.messagesGateway.server.to('admin_room').emit('support_unread_update', { unreadTotal });
}
// If admin sent the message, notify the user directly
if (senderRole === 'ADMIN') {
const chat = await this.supportChatService.getChat(chatId, userId, true);
this.messagesGateway.sendToUser(chat.userId, 'support_new_message', message);
}
return message;
}
// ==========================================
// MARK AS READ
// ==========================================
@Patch(':id/read')
@HttpCode(HttpStatus.OK)
@ApiOperation({ summary: 'Mark support chat messages as read' })
@ApiParam({ name: 'id', description: 'Support Chat ID' })
async markAsRead(
@Param('id') chatId: string,
@CurrentUser('role') role: UserRole,
) {
const result = await this.supportChatService.markAsRead(chatId, role);
// If admin marked as read, update sidebar badge for all admins
if (role === UserRole.ADMIN) {
const unreadTotal = await this.supportChatService.getAdminUnreadTotal();
this.messagesGateway.server.to('admin_room').emit('support_unread_update', { unreadTotal });
}
return result;
}
// ==========================================
// ADMIN: GET TOTAL UNREAD COUNT
// ==========================================
@Get('admin/unread-total')
@Roles(UserRole.ADMIN)
@ApiOperation({ summary: 'Admin: Get total unread support message count' })
@ApiResponse({ status: 200, description: 'Total unread count returned' })
async getUnreadTotal() {
return this.supportChatService.getAdminUnreadTotal();
}
// ==========================================
// ADMIN: GET ALL SUPPORT CHATS
// ==========================================
@Get('admin/all')
@Roles(UserRole.ADMIN)
@ApiOperation({ summary: 'Admin: Get all support chats' })
@ApiQuery({ name: 'status', required: false, enum: SupportChatStatus })
async getAllChats(@Query('status') status?: SupportChatStatus) {
return this.supportChatService.getAllChats(status);
}
// ==========================================
// ADMIN: CLOSE SUPPORT CHAT
// ==========================================
@Patch('admin/:id/close')
@Roles(UserRole.ADMIN)
@HttpCode(HttpStatus.OK)
@ApiOperation({ summary: 'Admin: Close a support chat' })
@ApiParam({ name: 'id', description: 'Support Chat ID' })
async closeChat(@Param('id') chatId: string) {
return this.supportChatService.closeChat(chatId);
}
}